面试题答案
一键面试内存管理规则与注意事项
- 遵循桥接规则
- ARC对Objective - C对象自动管理内存:在ARC环境下,Objective - C对象的内存由ARC自动处理,创建对象时,ARC会自动分配内存,对象不再被引用时,ARC会自动释放内存。
- Core Foundation对象需手动管理内存:Core Foundation框架使用的是传统的引用计数方式管理内存,需要开发者手动调用
CFRetain
增加引用计数,调用CFRelease
减少引用计数。当引用计数为0时,对象内存被释放。
- 对象所有权转换
- 桥接类型:
- Toll - free桥接:某些Objective - C对象和Core Foundation对象之间存在toll - free桥接关系,如
NSString
和CFStringRef
,NSArray
和CFArrayRef
等。这意味着可以在不进行显式转换的情况下将一种类型当作另一种类型使用,但内存管理规则仍需遵循各自的体系。例如,当通过toll - free桥接从NSString
获取CFStringRef
时,如果要释放CFStringRef
,仍需调用CFRelease
,因为ARC不会管理Core Foundation对象的内存。 - 显示桥接:分为
__bridge
、__bridge_retained
和__bridge_transfer
。__bridge
:用于简单地将Objective - C对象指针转换为Core Foundation对象指针(或反之),不改变对象的所有权。例如:
NSString *objcString = @"Hello"; CFStringRef cfString = (__bridge CFStringRef)objcString; // 这里ARC仍管理objcString的内存,CFStringRef不改变objcString的所有权
__bridge_retained
:将Objective - C对象指针转换为Core Foundation对象指针,并将对象的所有权从ARC转移到Core Foundation,需要手动调用CFRelease
释放对象。例如:
NSString *objcString = @"Hello"; CFStringRef cfString = (__bridge_retained CFStringRef)objcString; // 此时ARC不再管理objcString,需要手动CFRelease(cfString)释放内存 CFRelease(cfString);
__bridge_transfer
:将Core Foundation对象指针转换为Objective - C对象指针,并将对象的所有权从Core Foundation转移到ARC,ARC会在适当时候自动释放对象。例如:
CFStringRef cfString = CFStringCreateWithCString(kCFAllocatorDefault, "Hello", kCFStringEncodingUTF8); NSString *objcString = (__bridge_transfer NSString *)cfString; // 此时CFStringRef的所有权转移给ARC,无需手动释放cfString
- Toll - free桥接:某些Objective - C对象和Core Foundation对象之间存在toll - free桥接关系,如
- 桥接类型:
可能遇到的问题及解决方案
- 内存泄漏
- 问题:如果在使用
__bridge_retained
转换后忘记调用CFRelease
,或者在手动管理Core Foundation对象时没有正确平衡CFRetain
和CFRelease
,就会导致内存泄漏。例如:
NSString *objcString = @"Hello"; CFStringRef cfString = (__bridge_retained CFStringRef)objcString; // 没有调用CFRelease(cfString),导致内存泄漏
- 解决方案:仔细检查代码,确保在使用
__bridge_retained
转换后,在适当的地方调用CFRelease
。在手动管理Core Foundation对象时,严格按照引用计数规则,保证CFRetain
和CFRelease
成对出现。
- 问题:如果在使用
- 过早释放
- 问题:如果在使用
__bridge_transfer
转换后,又手动调用CFRelease
,就会导致对象被过早释放,后续访问该对象会引发程序崩溃。例如:
CFStringRef cfString = CFStringCreateWithCString(kCFAllocatorDefault, "Hello", kCFStringEncodingUTF8); NSString *objcString = (__bridge_transfer NSString *)cfString; CFRelease(cfString); // 这里导致对象过早释放,后续使用objcString会崩溃
- 解决方案:明确
__bridge_transfer
的语义,一旦使用__bridge_transfer
将对象所有权转移给ARC,就不要再手动调用Core Foundation的释放函数。
- 问题:如果在使用