面试题答案
一键面试ARC工作原理
ARC(自动引用计数)是一种内存管理机制,在编译时,编译器会自动在代码中合适的位置插入引用计数相关的代码。当对象被创建时,其引用计数初始化为1。每次有新的强指针指向该对象,引用计数加1;当指向对象的强指针不再指向该对象(比如指针超出作用域被销毁、指针被赋值为nil
等情况),引用计数减1。当对象的引用计数降为0时,ARC会自动释放该对象占用的内存空间。
可能出现内存泄漏的情况
- 循环引用:两个或多个对象之间相互持有强引用,形成一个循环,导致对象的引用计数永远不会降为0,从而无法释放内存。例如,对象A持有对象B的强引用,对象B又持有对象A的强引用,即使外部没有对A和B的引用,它们也无法被释放。
- 使用Core Foundation框架的对象:在ARC环境下,如果混合使用Objective-C对象和Core Foundation框架的对象,且没有正确地桥接,可能会导致内存管理问题。因为Core Foundation框架使用的是手动引用计数(MRC)方式,与ARC的规则不同。
避免泄漏的方法
- 解决循环引用:
- 使用弱引用(
weak
)或无主引用(unowned
):在可能出现循环引用的场景中,将其中一个对象对另一个对象的强引用改为弱引用或无主引用。弱引用不会增加对象的引用计数,当被引用的对象释放时,弱引用会自动被设置为nil
。无主引用也不会增加引用计数,但当被引用的对象释放后,无主引用指向的是一个已释放的内存地址,访问它会导致程序崩溃,所以无主引用适用于被引用对象的生命周期一定长于引用它的对象的场景。例如,在视图控制器中,视图控制器持有视图的强引用,视图中可能持有视图控制器的某个属性的引用,为避免循环引用,视图对视图控制器的引用可以设为弱引用。 - 使用块(block)时:在块内部如果捕获了对象,可能会形成循环引用。可以使用
__weak
修饰符来捕获对象,例如__weak typeof(self) weakSelf = self;
,然后在块内部使用weakSelf
,这样在块执行期间,如果self
被释放,weakSelf
会变为nil
,避免了循环引用。
- 使用弱引用(
- 处理Core Foundation对象:
- 正确桥接:在ARC环境下,当需要在Objective-C对象和Core Foundation对象之间转换时,使用适当的桥接函数。例如,
CFBridgingRelease
用于将Core Foundation对象转换为Objective-C对象并转移所有权给ARC,CFBridgingRetain
用于将Objective-C对象转换为Core Foundation对象并增加其引用计数。确保在使用完Core Foundation对象后,正确地释放其引用,以避免内存泄漏。
- 正确桥接:在ARC环境下,当需要在Objective-C对象和Core Foundation对象之间转换时,使用适当的桥接函数。例如,