24. 自动引用计数器

文章目录
  1. 1. ARC ⼯作机制
  2. 2. 解决实例之间的强引用循环
  3. 3. 解决闭包引起的强引⽤循环

官方目录:

  1. How ARC Works
  2. ARC in Action
  3. Strong Reference Cycles Between Class Instances
  4. Resolving Strong Reference Cycles Between Class Instances
  5. Strong Reference Cycles for Closures
  6. Resolving Strong Reference Cycles for Closures

引用计数只适用于实例对象。结构体和枚举是值类型,不是引用类型,并且不通过引用存储和传递的。

ARC ⼯作机制

解决实例之间的强引用循环

Swift 提供了两种方法解决你在使用类的属性而产生的强引用循环:弱引用( weak )和 无主引用( unowned )。

当一个实例的生命周期比较引用它的实例短,也就是这个实例可能会先于引用它的实例释放的时候,需要使用弱引用( weak )。对与一栋公寓来说在它的生命周期中是完全可以没有住户的,所以在这种情况下,上例中 Apartment 类使用弱引用来打断强引用循环是合 适的。相反,当一个实例拥有和引用它的实例相同的生命周期或是比引用它的实例更长的生命周期的时候,需要使用无主引用(unowned)。

由于弱引用需要能在运行过程中设置为 nil ,所以必需要声明为可选类型的变量而不是常量。

注意当 ARC 设置弱引用为 nil 的时候,属性观察不会被调用。

无主引用总是有值的。因而,ARC也不会将无主引用的值设置为 nil ,这也意味着无主引用要被定义为非可选类型。

总结来说:三种情况,

  1. 都可以为nil,weak
  2. 一个可为nil,unowned
  3. 都不能为nil, unowned和隐式解包可选值


其中第三种比较经典,下面列出代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Country {
let name: String
var capitalCity: City!
init(name: String, capitalName: String) {
self.name = name
self.capitalCity = City(name: capitalName, country: self)
}
}

class City {
let name: String
unowned let country: Country
init(name: String, country: Country) {
self.name = name
self.country = country
}
}

解决闭包引起的强引⽤循环

捕获列表:在闭包内部捕获一个或多个引用类型的规则

捕获列表中的每一项都是由 weak 或 unowned 关键字和实例的引用(如 self ) 或是由其他值初始化的变量(如 delegate = self.delegate! )成组构成的。它们每 一组都写在方括号中,组之间用逗号隔开。

捕获列表放在闭包的参数和返回值(如果有返回值的话)前面:

1
2
3
4
lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
// closure body goes here
}