Swift知识点23 - 自动引用计数

引用计数仅仅应用于类的实例。结构体和枚举类型是值类型,不是引用类型,也不是通过引用的方式存储和传递。

无论你将实例赋值给属性、常量或变量,它们都会创建此实例的强引用。之所以称之为“强”引用,是因为它会将实例牢牢地保持住,只要强引用还在,实例是不允许被销毁的。

如果两个类实例互相持有对方的强引用,因而每个实例都让对方一直存在,就是这种情况。这就是所谓的循环强引用。

你可以通过定义类之间的关系为弱引用或无主引用,以替代强引用,从而解决循环强引用的问题。

使用类属性遇到的强引用解决办法:

  1. 弱引用(weak reference)
  2. 无主引用(unowned reference)

什么时候使用weak和unowned?
unowned:同时销毁
weak:被捕获的self有可能比闭包销毁早

/*
 弱引用:被捕获的self比其他实例早销毁的话,用weak修饰
 无主引用:被捕获的self和其他实例同时销毁或者更晚的声明周期的话,用onwned修饰
 */

情况:self销毁了,闭包没有销毁,如果使用unowned的话,会出现崩溃,使用weak则没有问题。

当其他的实例有更短的生命周期时,使用弱引用。
当其他实例有相同的或者更长生命周期时,请使用无主引用。

无主引用:
无主引用在其他实例有相同或者更长的生命周期时使用。你可以在声明属性或者变量时,在前面加上关键字 unowned 表示这是一个无主引用。

和OC一样,Swift也是用ARC,也会有循环引用导致内存泄露
如果属性是可选类型,只能用weak修饰符避免循环引用。所引用对象被回收后改属性会被自动置为nil
如果属性不是可选类型,只能用无主引用(unowned)。所引用对象被回收后属性不会被置为nil,此时访问会导致运行时错误。类似OC中的unsafe_unretained修饰符。

Person 和 Apartment 的例子展示了两个属性的值都允许为 nil,并会潜在的产生循环强引用。这种场景最适合用弱引用来解决。

Customer 和 CreditCard 的例子展示了一个属性的值允许为 nil,而另一个属性的值不允许为 nil,这也可能会产生循环强引用。这种场景最适合通过无主引用来解决。

无主引用和隐式解析可选属性

在这种场景中,两个属性都必须有值,并且初始化完成后永远不会为 nil。在这种场景中,需要一个类使用无主属性,而另外一个类使用隐式解析可选属性。

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
    }
}

闭包的循环强引用

将一个闭包赋值个类实例的某一个属性,而这个闭包又使用了这个类实例时,使用了self,导致闭包捕获了self,引起强引用。

循环强引用的产生,是因为闭包和类一样,都是引用类型。

解决闭包的循环强引用:
声明每个捕获的引用为弱引用或无主引用,根据代码关系来决定使用弱引用还是无主引用。

Swift 有如下要求:只要在闭包内使用 self 的成员,就要用 self.someProperty 或者 self.someMethod()(而不只是 someProperty 或 someMethod())。这提醒你可能会一不小心就捕获了 self。

定义捕获列表

捕获列表中的每一项都由一对元素组成,一个元素是 weak 或 unowned 关键字,另一个元素是类实例的引用(例如 self)或初始化过的变量(如 delegate = self.delegate!)。这些项在方括号中用逗号分开。

lazy var someClosure: (Int, String) -> String = {
    [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
    // 这里是闭包的函数体
}

在闭包和捕获的实例总是互相引用并且总是同时销毁时,将闭包内的捕获定义为 无主引用。

相反的,在被捕获的引用可能会变为 nil 时,将闭包内的捕获定义为 弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为 nil。这使我们可以在闭包体内检查它们是否存在。

如果被捕获的引用绝对不会变为 nil,应该用无主引用,而不是弱引用。

你可能感兴趣的:(Swift知识点23 - 自动引用计数)