面试题答案
一键面试ARC(自动引用计数)和MRC(手动引用计数)的区别
- 内存管理方式:
- MRC:开发者需要手动管理对象的内存,通过调用
retain
、release
和autorelease
等方法来控制对象的引用计数。例如,当创建一个对象时,需要手动调用retain
增加引用计数,在不再使用该对象时,调用release
减少引用计数。如果引用计数降为0,对象的内存会被释放。 - ARC:编译器会自动在适当的位置插入
retain
、release
和autorelease
代码。开发者无需手动调用这些方法,ARC会根据对象的生命周期自动管理内存,大大减轻了开发者的负担,减少了因手动管理不当导致的内存泄漏和悬空指针等问题。
- MRC:开发者需要手动管理对象的内存,通过调用
- 代码复杂度:
- MRC:代码中需要频繁地插入内存管理代码,使代码变得冗长和复杂,增加了开发和维护的难度。
- ARC:代码更加简洁,开发者可以更专注于业务逻辑的实现,提高开发效率。
- 错误风险:
- MRC:手动管理内存容易出现错误,比如过度释放对象导致程序崩溃,或者忘记释放对象导致内存泄漏。
- ARC:自动管理内存减少了这些错误的发生概率,提高了程序的稳定性。
ARC环境下处理循环引用问题及举例
- 处理方式:
- 弱引用(__weak):使用
__weak
关键字修饰属性或变量,被__weak
修饰的对象不会增加引用计数。当对象的强引用计数降为0被释放时,指向该对象的__weak
指针会自动被设置为nil
,从而避免了循环引用。 - 无主引用(__unsafe_unretained):与
__weak
类似,__unsafe_unretained
修饰的对象也不会增加引用计数。但与__weak
不同的是,当对象被释放后,指向该对象的__unsafe_unretained
指针不会被自动设置为nil
,可能会导致野指针访问,使用时需要更加小心。一般情况下,优先使用__weak
,只有在不能使用__weak
(如iOS 4.0及之前版本不支持__weak
)时才考虑使用__unsafe_unretained
。
- 弱引用(__weak):使用
- 举例:
假设我们有两个类
Person
和Dog
,Person
类中有一个Dog
类型的属性,Dog
类中有一个Person
类型的属性,如果都使用强引用,就会出现循环引用。
@interface Dog : NSObject
@property (nonatomic, strong) Person *owner;
@end
@interface Person : NSObject
@property (nonatomic, strong) Dog *pet;
@end
在上述代码中,Person
持有Dog
的强引用,Dog
又持有Person
的强引用,形成了循环引用。
解决办法是将其中一个引用改为弱引用,例如:
@interface Dog : NSObject
@property (nonatomic, __weak) Person *owner;
@end
@interface Person : NSObject
@property (nonatomic, strong) Dog *pet;
@end
这样,当Person
对象被释放时,Dog
对象对Person
的引用不会阻止Person
的释放,从而打破了循环引用。同样,如果将Person
类中的pet
属性改为__weak
也可以达到同样的效果。