MST

星途 面试题库

面试题:Objective-C中ARC下的循环引用问题及解决方案

在ARC环境下,举例说明可能会出现循环引用的场景,并详细描述至少两种解决循环引用的方法及其原理。
42.1万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

可能出现循环引用的场景举例

在ARC(自动引用计数)环境下,一个常见的循环引用场景是两个对象相互持有对方的强引用。例如:

@interface ClassA : NSObject
@property (strong, nonatomic) ClassB *classB;
@end

@interface ClassB : NSObject
@property (strong, nonatomic) ClassA *classA;
@end

@implementation ClassA
@end

@implementation ClassB
@end

在上述代码中,如果创建 ClassAClassB 的实例,并相互赋值对方的属性:

ClassA *a = [[ClassA alloc] init];
ClassB *b = [[ClassB alloc] init];
a.classB = b;
b.classA = a;

此时 ab 有一个强引用,ba 也有一个强引用,形成了循环引用。当超出作用域时,由于双方的强引用导致对方的引用计数不会降为0,从而无法被释放。

解决循环引用的方法及其原理

1. 使用弱引用(weak

  • 方法:将其中一个对象的属性改为 weak 类型。例如,修改 ClassBclassA 属性为 weak
@interface ClassB : NSObject
@property (weak, nonatomic) ClassA *classA;
@end
  • 原理weak 引用不会增加对象的引用计数。当对象的强引用计数变为0被释放时,指向该对象的所有 weak 引用会自动被设置为 nil。在上述例子中,ClassAClassB 是强引用,ClassBClassA 是弱引用。当 ClassA 的其他强引用都消失后,其引用计数变为0被释放,此时 ClassBclassA 属性自动变为 nil,从而打破了循环引用。

2. 使用无主引用(unowned

  • 方法:在某些情况下,比如确定两个对象的生命周期相同且相互依赖,可以使用 unowned 引用。例如,在Swift中:
class ClassA {
    var classB: ClassB?
    init() {
        classB = ClassB(a: self)
    }
}

class ClassB {
    unowned let classA: ClassA
    init(a: ClassA) {
        classA = a
    }
}
  • 原理unowned 引用和 weak 类似,不会增加对象的引用计数。不同的是,unowned 引用在对象被释放后不会被设置为 nil,因此使用 unowned 时要确保引用的对象在其生命周期内始终存在,否则会导致野指针错误。在上述例子中,ClassA 持有 ClassB 的强引用,ClassB 持有 ClassAunowned 引用,由于 ClassA 先初始化 ClassB,且二者生命周期相关,所以可以使用 unowned 打破循环引用。