面试题答案
一键面试循环引用场景举例
在Objective-C中,当两个对象相互持有对方的强引用属性时,就会出现循环引用。例如:
@interface ClassA : NSObject
@property (nonatomic, strong) ClassB *classB;
@end
@interface ClassB : NSObject
@property (nonatomic, strong) ClassA *classA;
@end
假设在某个地方创建了这两个类的实例,并相互赋值:
ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];
a.classB = b;
b.classA = a;
此时a
强引用b
,b
又强引用a
,即使a
和b
超出作用域,由于它们相互持有对方,引用计数不会降为0,导致内存泄漏。
解决循环引用的方法及原理
- 使用弱引用(
weak
) 原理:弱引用不会增加对象的引用计数。当对象的引用计数降为0并被销毁时,指向该对象的所有弱引用会自动被设置为nil
。 在上述例子中,修改ClassB
的classA
属性为弱引用:
@interface ClassB : NSObject
@property (nonatomic, weak) ClassA *classA;
@end
这样,b
对a
的引用不会增加a
的引用计数,当a
的其他强引用都被释放后,a
的引用计数降为0并被销毁,此时b.classA
自动变为nil
,从而打破循环引用。
- 使用无主引用(
unowned
) 原理:无主引用同样不会增加对象的引用计数。与弱引用不同的是,当被引用的对象销毁后,指向它的无主引用不会自动被设置为nil
,如果此时访问无主引用指向的已销毁对象,会导致程序崩溃。所以使用无主引用时要确保被引用对象的生命周期长于引用它的对象。 在上述例子中,修改ClassB
的classA
属性为无主引用:
@interface ClassB : NSObject
@property (nonatomic, unowned) ClassA *classA;
@end
这种方法适用于能确保ClassA
实例的生命周期比ClassB
实例长的场景,同样可以打破循环引用。