MST

星途 面试题库

面试题:Swift中ARC机制如何处理循环引用问题

请描述在Swift中,ARC(自动引用计数)机制是怎样检测和处理循环引用的场景,并举出至少一种常见的循环引用场景及解决办法。
23.4万 热度难度
编程语言Swift

知识考点

AI 面试

面试题答案

一键面试

ARC检测和处理循环引用场景的机制

ARC 通过跟踪对象的引用计数来管理内存。当一个对象的引用计数变为 0 时,ARC 会自动释放该对象所占用的内存。在循环引用场景下,两个或多个对象相互持有强引用,导致它们的引用计数永远不会变为 0 ,从而造成内存泄漏。ARC 采用弱引用(weak)和无主引用(unowned)来打破这种循环引用。

常见循环引用场景及解决办法

  1. 闭包引起的循环引用
    • 场景:当一个闭包捕获了它所在类的实例(self),同时这个闭包又被该实例所持有,就会形成循环引用。例如,一个视图控制器持有一个闭包属性,闭包内又访问了视图控制器的属性或方法。
    • 解决办法:使用[weak self][unowned self]在闭包捕获列表中捕获self
class ViewController: UIViewController {
    var closure: (() -> Void)?

    override func viewDidLoad() {
        super.viewDidLoad()
        closure = { [weak self] in
            guard let self = self else { return }
            print(self.view)
        }
    }
}
  1. 两个类相互持有强引用
    • 场景:假设有两个类ClassAClassBClassA有一个ClassB类型的强引用属性,ClassB也有一个ClassA类型的强引用属性。
class ClassA {
    var b: ClassB?
    deinit {
        print("ClassA deinit")
    }
}

class ClassB {
    var a: ClassA?
    deinit {
        print("ClassB deinit")
    }
}

如果这样创建实例:

var a = ClassA()
var b = ClassB()
a.b = b
b.a = a
a = nil
b = nil
// 此时ClassA和ClassB不会被销毁,因为它们相互持有强引用
- **解决办法**:将其中一个类的引用改为弱引用或无主引用。例如将`ClassB`中的`a`属性改为弱引用:
class ClassB {
    weak var a: ClassA?
    deinit {
        print("ClassB deinit")
    }
}

这样当ab被置为nil时,两个实例就会被正常销毁。