Appearance
Swift 入门(19):内存管理
Swift 使用 ARC(Automatic Reference Counting) 自动管理内存,大多数情况下不需要手动释放对象。但理解其工作原理非常重要,尤其是避免循环引用。
1. ARC 的基本原理
- 每个类实例都有一个 引用计数。
- 当引用 +1 时,实例保留。
- 当引用变为 0 时,实例被销毁。
swift
class Person {
let name: String
init(name: String) { self.name = name }
deinit { print("\(name) 被销毁") }
}
var p1: Person? = Person(name: "Tom")
p1 = nil // 引用计数归零,触发 deinit2. 强引用(Strong Reference)
默认情况下,变量保存对象时会创建一个 强引用。
swift
class Dog {}
var d1: Dog? = Dog()
var d2 = d1 // d1, d2 都是强引用3. 循环引用问题
如果两个对象相互持有强引用,会导致 循环引用,对象无法释放。
swift
class Teacher {
var student: Student?
deinit { print("Teacher deinit") }
}
class Student {
var teacher: Teacher?
deinit { print("Student deinit") }
}
var t: Teacher? = Teacher()
var s: Student? = Student()
t?.student = s
s?.teacher = t
t = nil
s = nil
// ❌ Teacher 和 Student 都不会释放4. 解决循环引用
4.1 弱引用(weak)
- 用
weak修饰,引用不会增加计数。 - 常用于 可选类型,引用对象销毁后会自动设为
nil。
swift
class Teacher {
var student: Student?
deinit { print("Teacher deinit") }
}
class Student {
weak var teacher: Teacher? // 🔑 解决循环引用
deinit { print("Student deinit") }
}4.2 无主引用(unowned)
- 用
unowned修饰,不会增加计数。 - 不会自动置 nil,适合生命周期一致的对象。
swift
class CreditCard {
unowned let customer: Customer // 永远存在
init(customer: Customer) { self.customer = customer }
deinit { print("Card deinit") }
}
class Customer {
var card: CreditCard?
deinit { print("Customer deinit") }
}
var c: Customer? = Customer()
c?.card = CreditCard(customer: c!)
c = nil // 两个对象都释放5. 闭包捕获列表
闭包也可能导致循环引用,需要用 [weak self] 或 [unowned self]。
swift
class ViewController {
var name = "VC"
var callback: (() -> Void)?
func setup() {
callback = { [weak self] in
print(self?.name ?? "nil")
}
}
deinit { print("VC deinit") }
}总结
- Swift 使用 ARC 自动管理内存。
- 循环引用是主要问题,需要
weak或unowned解决。 - 闭包中捕获
self时,注意使用捕获列表。