Swift 中的内存管理机制是什么?什么是 ARC(自动引用计数)?如何避免循环引用?
Swift 使用自动引用计数(ARC)来自动管理应用程序的内存。ARC 会跟踪和管理应用程序使用的内存,并在实例不再需要时自动释放内存。
ARC 的工作原理:
- 每次创建类实例的新引用时,ARC 会增加该实例的引用计数
- 当引用被移除时,ARC 会减少引用计数
- 当引用计数降为零时,ARC 会释放该实例的内存
- ARC 只适用于类类型的实例,结构体和枚举是值类型,不参与引用计数
强引用循环:
- 两个或多个类实例相互持有强引用,导致引用计数永远不会降为零
- 常见场景:类之间的相互引用、闭包捕获类实例
- 示例:
swift
class Person { var apartment: Apartment? } class Apartment { var tenant: Person? } let person = Person() let apartment = Apartment() person.apartment = apartment apartment.tenant = person
解决循环引用的方法:
-
弱引用:
- 使用
weak关键字声明 - 不会增加引用计数
- 引用的对象被释放后,弱引用会自动变为 nil
- 必须声明为可选类型
- 适用于引用可能为 nil 的情况
- 示例:
swift
class Apartment { weak var tenant: Person? }
- 使用
-
无主引用:
- 使用
unowned关键字声明 - 不会增加引用计数
- 引用对象被释放后,无主引用不会自动变为 nil
- 不能声明为可选类型
- 适用于引用对象生命周期更长的情况
- 示例:
swift
class Customer { let creditCard: CreditCard init(creditCard: CreditCard) { self.creditCard = creditCard } } class CreditCard { unowned let customer: Customer }
- 使用
-
闭包中的循环引用:
- 使用捕获列表
[weak self]或[unowned self] - 示例:
swift
class HTMLElement { let name: String lazy var asHTML: () -> String = { [weak self] in guard let self = self else { return "" } return "<\(self.name)>" } }
- 使用捕获列表
最佳实践:
- 在类属性中使用
weak或unowned避免强引用循环 - 在闭包中使用捕获列表处理循环引用
- 使用
weak当引用可能为 nil 时 - 使用
unowned当引用对象生命周期更长时 - 使用 Instruments 工具检测内存泄漏