每天学一点Swift----面向对象下(十)

43 篇文章 0 订阅
42 篇文章 0 订阅

十九. Swift内存管理

1. Swift提供了强大的内存管理机制:Swift通过自动引用计数(ARC)可以很好地管理对象的回收。大部分时候,程序无须关心Swift对象的回收,但在某些特殊情况下,Swift要求程序员进行一些内存管理的处理。


2. 只有引用类型变量所引用的对象才需要使用引用计数进行管理,对于枚举、结构体,他们是值类型,因此不需要使用引用计数进行管理。


3. ARC是一种非常优秀的内存管理技术,它的实现思路非常简单:当程序在内存中创建一个对象之后,ARC将会自动完成两件事情:

1ARC自动统计该对象被多少个引用变量所引用,这个值就被称为引用计数。简单地说,ARC相当于为每个对象额外增加了一个Int类型的属性,该属性总能正确地记录有多少个引用变量在引用该对象。

2)每当一个对象的引用计数为0时,ARC会自动回收该对象。


4. 没有必要去了解ARC到底是如何统计的,使用ARC之后,程序甚至不允许直接访问对象的引用计数。


5. 强引用:大部分时候,ARC可以很好地处理程序中对象的内存回收,但如果两个对象之间存在双向关联:两个对象都使用存储属性互相引用对方的时候,此时两个对象的引用计数都等于1,但它们实际上并没有被真正的引用变量所引用,但ARC也无法回收它们。如果没有特殊说明,Swift中的引用变量都是强引用,此时两个对象形成了强引用循环。


6. 为了解决上面的强引用循环,必须有一方做出让步,允许对方先释放,这样问题就解决了。Swift为解决强引用循环提供了两种解决机制:弱引用和无主引用。


7.使用弱引用解决强引用循环:弱应用不会增加对方的引用计数,因此不会阻止ARC回收被引用的实例,这样就可以避免形成强引用循环。在定义属性的var关键字前面使用weak关键字即可定义弱引用。


8. 弱应用变量要求该应用变量  ***必须*** 允许被设为nil,也就是弱应用是可以没有值的,所以推荐使用可选类型来定义弱引用属性。


9. 弱应用只能声明为变量类型,因为该属性在允许期间内值有可能发生改变,因此弱引用决不能声明为常量。


10. 由于弱引用不会持有实例,因此即使弱引用存在,ARC也可能会销毁实例,并将弱引用变量赋值为nil,所以程序可以像检查其他可选类型的变量一样检查弱引用是否存在,这样就永远不会出现调用了被销毁实例的情形。


11. 使用弱引用非常简单,只要将相互引用的两方中的任意一方的关联属性使用weak修饰即可,举个栗子:

class Student

{

   var name  : String

   var skill : String

   //使用弱引用持有Teacher对象

   weak var teacher : Teacher?

   

   init(name : String, skill : String)

   {

self.name = name

self.skill = skill

   }

   deinit{

     print("teacher will be destoryed")

   }

}


12. 使用无主引用解决强引用循环:无主引用也不会增加对方的引用计数。无主引用与弱引用的区别是:无主引用不允许接受nil(即应该始终有值),因此无主引用只能定义为非可选类型。在定义属性的varlet关键字之前添加unowned关键字即可定义无主引用。


13. 因为无主引用是非可选类型的,因此当使用使用无主引用时不需要强制解析,可以直接访问。但由于非可选类型的属性不能为nil,因此当ARC回收了引用变量属性所引用的实例之后,ARC无法将该引用变量属性赋值为nil


14. 当无主引用所引用的对象被销毁之后,无主引用变量并没有被赋值为nil,因此程序无法准确判断无主引用所引用的对象是否已经被销毁。如果程序试图通过无主引用去调用被销毁的实例,将会导致运行时错误。


15. 弱引用和无主引用的实例覆盖了两种常用的场景:

1)如果两个实体中记录关联实体的属性都可能是nil,并有可能产生强引用循环,此时适合使用弱引用。

2)如果两个实体中记录关联实体的属性一个是nil,另一个不能是nil,并有可能产生强引用循环,此时适合使用无主引用。

还有一种情况:两个属性都必须有值,且初始化后都不会为nil,并有可能产生强引用循环,此时要求一个类使用无主引用,另一个类使用隐式可选属性。


16. 闭包与对象的强引用循环:如果累的某个属性不是普通类型,而是函数类型,那么这个属性就有可能返回一个闭包。闭包会捕获传入其中的引用变量----如果程序将该对象本身传入了闭包,那么闭包本身就会捕获该对象,于是该对象就持有了闭包属性;反过来,闭包也持有了该对象,这样对象和闭包也形成了强引用循环。


17. 解决闭包与对象之间的强引用循环时,到底采用弱引用还是无主引用,也需要根据实际场景来选择。当闭包和捕获的实例总是相互引用,且总是同时销毁时,应该将闭包内捕获的实例定义为无主引用。相反的,当闭包捕获的引用变量有可能是nil时,将闭包捕获的引用变量定义为弱引用。弱引用必须是可选类型,当被引用的实例被销毁后,弱引用的变量会自动被赋值为nil


18. Swift通过为闭包定义捕获列表来指定捕获变量应该采用弱引用,还是采用无主引用。语法格式如下:

{[unowned|weak 捕获变量](形参列表) ->返回值类型 in

   //闭包执行体

}

如果闭包无须定义形参、返回值类型,则该闭包语法格式为:

{[unowned|weak 捕获变量] in

   //闭包执行体

}

可以看出,捕获列表总是定义在闭包的第一行,且使用方括号括起来,每个捕获变量都需要unowned或者weak修饰。


19. 举个栗子:

class Student

{

   var name : String

   var age : Int

   lazy var stuInfo : () -> String ={

   //定义捕获列表,指定闭包中self引用变量是无主引用

   [unowned self] in 

   "\(self.name),\(self.age)"

   }


   init(name : String, age : Int)

   {

self.name = name

self.age = age

   }

   //定义析构器

   deinit{

      print("student will be deinit")

   }

}


var stu : Student? = Student(name : "xiaoming", age : 12)

var info : (() -> String)? = stu!.stuInfo

stu = nil

info = nil


由于无主引用不会增加对方的引用计数,因此在程序中Student对象的计数为0,于是ARC将会先释放内存中的Student对象。当Student对象被释放之后,Student的属性就不复存在了,此时Student对象也就不再引用内存中的闭包了,于是闭包的引用计数也变为0ARC会释放闭包。


上一篇:每天学一点Swift----面向对象下(九)

下一篇:每天学一点Swift----泛型(一)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值