Swift的循环引用以weak

什么是循环引用

Swift 是自动管理内存的,这也就是说,我们不再需要操心内存的申请和分配。当我们通过初始化创建一个对象时,Swift 会替我们管理和分配内存。而释放的原则遵循了自动引用计数 (ARC) 的规则:当一个对象没有引用的时候,其内存将会被自动回收。这套机制从很大程度上简化了我们的编码,我们只需要保证在合适的时候将引用置空 (比如超过作用域,或者手动设为 nil 等),就可以确保内存使用不出现问题。
但是,所有的自动引用计数机制都有一个从理论上无法绕过的限制,那就是循环引用 (retain cycle) 的情况。
假设我们有两个类 A 和 B, 它们之中分别有一个存储属性持有对方:

class A {
   let b: B
   init() {
       b = B()
       b.a = self
   }

   deinit {
       println("A deinit")
   }
}
class B {
   var a: A? = nil
   deinit {
       println("B deinit")
  }
}

在 A 的初始化方法中,我们生成了一个 B 的实例并将其存储在属性中。然后我们又将 A 的实例赋值给了 b.a。这样 a.b 和 b.a 将在初始化的时候形成一个引用循环。现在当有第三方的调用初始化了 A,然后即使立即将其释放,A 和 B 两个类实例的 deinit 方法也不会被调用,说明它们并没有被释放。

func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) 
             -> Bool {

    // Override point for customization after application launch.

    var obj: A? = A()
    obj = nil
    // 内存没有释放

    return true
}
在 Swift 里防止循环引用

为了防止这种人神共愤的悲剧的发生,我们必须给编译器一点提示,表明我们不希望它们互相持有。一般来说我们习惯希望 "被动" 的一方不要去持有 "主动" 的一方。在这里 b.a 里对 A 的实例的持有是由 A 的方法设定的,我们在之后直接使用的也是 A 的实例,因此认为 b 是被动的一方。可以将上面的 class B 的声明改为:

class B {
    weak var a: A? = nil
    deinit {
        println("B deinit")
    }
}

在 var a 前面加上了 weak,向编译器说明我们不希望持有 a。这时,当 obj 指向 nil 时,整个环境中就没有对 A 的这个实例的持有了,于是这个实例可以得到释放。接着,这个被释放的实例上对 b 的引用 a.b 也随着这次释放结束了作用域,所以 b 的引用也将归零,得到释放。添加 weak 后的输出:

A deinit
B deinit

总体说下来,我理解为在声明的时候,被动一方需要加上weak

其他一个例子

比如实现如下一个自定义控件

BlueSlider-480x94.png
BlueSlider-480x94.png

定义整个控件为RangeSlider

import UIKit 

class RangeSlider: UIControl { 

}

把这个控件的按钮定义为一个继承自CALayer的类,起名字叫RangeSliderThumbLayer,因为有两个,所以有

let lowerThumbLayer = RangeSliderThumbLayer() 
let upperThumbLayer = RangeSliderThumbLayer()

更上边合成后RangeSlider类现在为这个样子
import UIKit

class RangeSlider: UIControl { 
    let lowerThumbLayer = RangeSliderThumbLayer() 
    let upperThumbLayer = RangeSliderThumbLayer() 
}

那么RangeSliderThumbLayer应该是什么样子呢,如下:

import UIKit 
import QuartzCore 

class RangeSliderThumbLayer: CALayer { 
    weak var rangeSlider: RangeSlider? 
}

在这里,rangeSlider引用回父 range slider。由于 RangeSlider 有两个 thumb layer,所以将这里的引用设置位 weak,避免循环引用。

那么此时在RangeSlider类中加入以下就不会出现问题了

lowerThumbLayer.rangeSlider = self 
upperThumbLayer.rangeSlider = self

此时,RangeSliderThumbLayer是被动方,所以在其中写上weak


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值