Swift weak 与 unowned

在用 Swift 做开发时,我们可以使用 weak 或是 unowned 打破类实例和闭包的强引用循环。我们来看下 weak 和 unowned 的相同和不同之处。

weak

日常开发中,我们经常会用weak来标记代理或者在闭包中使用它来避免引用循环。

weak var delegate: SomeDelegate?

lazy var someClosure: () -> Void = { [weak self] in
    guard let self = self else { retrun }
    self.balabala
}

当我们赋值给一个被标记weak的变量时,它的引用计数不会被改变。而且当这个弱引用变量所引用的对象被释放时,这个变量将被自动设为nil。这也是弱引用必须被声明为Optional的原因。

unowned

weak相同,unowned也可以在不增加引用计数的前提下,引用某个类实例。

unowned let someInstance: SomeClass

lazy var someClosure: () -> Void = { [unowned self] in
    self.balabala
}

在使用unowned时,我们不需要将变量声明为Optional
需要注意的是。对于被unowned标记的变量,即使它的原来引用已经被释放,它仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不是Optional ,也不会被指向 nil。所以,当我们试图访问这样的unowned引用时,程序就会发生错误。

看这个描述是不是有点眼熟,作为 iOS 开发的老司机,这东西像不像OC里的 __unsafe_unretained

__weak对性能会有一定的消耗,使用__weak,需要检查对象是否被释放,在追踪是否被释放的时候当然需追踪一些信息,那么此时__unsafe_unretained__weak快,而且一个对象有大量的__weak引用对象的时候当对象被废弃,那么此时就要遍历weak表,把表里所有的指针置空,消耗cpu资源。

不过我感觉这东西真的没必要,比起 crash, 这点性能真的没必要。