Swift中的自动引用计数
ARC
- Swift使用自动引用计数(ARC)来跟踪并管理应用使用的内存。大部分情况下,这意味着在Swift语音中,内存管理“仍然工作”,不需要自己去考虑内存管理的事情。当实例不再被使用时,ARC会自动释放这些类的实例所占用的内存
- 引用计数只应用在类的实例。结构体(Structure)和枚举类型是值类型,并非引用类型,不是以引用的方式来存储和传递的
ARC如何工作
循环引用
- 在两个类实例彼此保持对方的强引用,使得每个实例都使对方保持有效时会发生这种情况。我们称之为强引用
- 通过用弱引用或者无主引用来取代强引用,我们可以解决强引用环问题
解决循环引用
- 弱引用和无主引用允许引用环中的一个实例引用另外一个实例,但不是强引用。因为实例可以互相引用但是不会产生强引用环
- 对于生命周期中引用会变为nil的实例,使用弱引用;对于初始化时赋值之后引用再也不会赋值为nil的实例,使用无主引用
弱引用
- 弱引用不会增加实例的引用计数,因为不会阻止ARC销毁被引用的实例。这种特性使得引用不会变成强引用环。声明属性或者变量的时候,关键字weak表明引用为弱引用
- 弱引用只能声明为变量类型,因为运行时它的值可能改变。弱引用绝对不能声明为常量
- 因为弱引用可以没有值,所以声明弱引用的时候必须是可选类型的。在Swift语音中,推荐可选类型来作为可能没有值的引用的类型
无主引用
- 和弱引用相似,无主引用也不强持有实例。但是和弱引用不同的是,无主引用默认始终有值。因此,无主引用只能定义为非可选类型(non-optional type)。在属性、变量前添加unowned关键字,可以声明一个无主引用
- 因为是非可选类型,因为当使用无主引用的时候,不需要展开,可以直接访问。不过非可选类型变量不能赋值为nil, 因此当实例被销毁的时候,ARC无法将引用赋值为nil
- 当实例被销毁后,试图访问该实例的无主引用会触发运行时错误。使用无主引用时请确保引用始终指向一个未销毁的实例
闭包引用循环
- 将一个闭包赋值给类实例的某个属性,并且这个闭包使用了实例,这样也会产生强引用环。这个闭包可能访问了实例的某个属性,例如self.someProperty,或者调用了实例的某个方法,例如self.someMethod。这两种情况都导致了闭包使用self,从而产生了循环引用
闭包引用循环解决
- 定义占有列表 - 占有列表中的每个元素都是有weak或者unowned关键字和实例的引用(如self或somInstance)组成。每一对都在括号中,通过逗号分开
- 当闭包和占有的实例总是互相引用时并且总是同时销毁时,将闭包内的占有定义为无主引用
- 相反的,当占有引用有时会是nil时,将闭包内的占有定义为弱引用
Swift中的内存安全性
内存安全
- 访问可以分两种
- 即时访问: 即在访问开始至结束前都不可能有其他代码来访问同一区域
- 长期访问:即在访问开始至结束前可能有其他代码来访问同一区域。长期访问可能和其他即时访问或者长期访问重叠
inout参数访问冲突
inout参数访问冲突解决
self访问冲突