设为首页 加入收藏

TOP

【Swift学习】Swift编程之旅---ARC(二十)(二)
2017-10-13 10:33:52 】 浏览:10392
Tags:Swift 学习 编程 之旅 ---ARC 二十

 现在你可以将两个实例关联起来,一个人拥有一所公寓,一个公寓也拥有一个房客。注意:用感叹号(!)来展开并访问可选类型的变量,只有这样这些变量才能被赋值:

john!.apartment = unit4A unit4A!.tenant = john

 

 实例关联起来后,强引用关系如下图所示

 

 关联这俩实例生成了一个强循环引用,Person实例和Apartment实例各持有一个对方的强引用。因此,即使你破坏john和number73所持有的强引用,引用计数也不会变为0,因此ARC不会销毁这两个实例

 

john = nil
unit4A = nil

当上面两个变量赋值为nil时,没有调用任何一个析构方法。强引用阻止了Person和Apartment实例的销毁,进一步导致内存泄漏。

 

  避免强引用循环

  Swift提供两种方法避免强引用循环:弱引用和非持有引用。 

   对于生命周期中引用会变为nil的实例,使用弱引用;对于初始化时赋值之后引用再也不会赋值为nil的实例,使用非持有引用。

 

  弱引用

  弱引用不会增加实例的引用计数,因此不会阻止ARC销毁被引用的实例,声明属性或者变量的时候,关键字weak表明引用为弱引用。弱引用只能声明为变量类型,因为运行时它的值可能改变。弱引用绝对不能声明为常量

   因为弱引用可以没有值,所以声明弱引用的时候必须是可选类型的。在Swift语言中,推荐用可选类型来作为可能没有值的引用的类型。

 下面的例子和之前的Person和Apartment例子相似,除了一个重要的区别。这一次,我们声明Apartment的tenant属性为弱引用:

class Person { let name: String init(name: String) { self.name = name } var apartment: Apartment? deinit { print("\(name) is being deinitialized") } } class Apartment { let unit: String init(unit: String) { self.unit = unit } weak var tenant: Person? deinit { print("Apartment \(unit) is being deinitialized") } }

 

 然后创建两个变量(john和unit4A)的强引用,并关联这两个实例:

var john: Person?
var unit4A: Apartment? john = Person(name: "John Appleseed") unit4A = Apartment(unit: "4A") john!.apartment = unit4A unit4A!.tenant = john

 

 下面是引用的关系图:

 

Person的实例仍然是Apartment实例的强引用,但是Apartment实例则是Person实例的弱引用。这意味着当破坏john变量所持有的强引用后,不再存在任何Person实例的强引用: 

 

 既然不存在Person实例的强引用,那么该实例就会被销毁:

 

    非持有引用
 
和弱引用相似,非持有引用也不强持有实例。但是和弱引用不同的是,非持有引用默认始终有值。因此,非持有引用只能定义为非可选类型(non-optional type)。在属性、变量前添加unowned关键字,可以声明一个非持有引用。
 
因为是非可选类型,因此当使用非持有引用的时候,不需要展开,可以直接访问。不过非可选类型变量不能赋值为nil,因此当实例被销毁的时候,ARC无法将引用赋值为nil。
 
 
class Customer { let name: String var card: CreditCard? init(name: String) { self.name = name } deinit { println("\(name) is being deinitialized") } class CreditCard { let number: Int unowned let customer: Customer init(number: Int, customer: Customer) { self.number = number self.customer = customer } deinit { println("Card #\(number) is being deinitialized") } 

 

下面的代码定义了一个叫john的可选类型Customer变量,用来保存某个特定消费者的引用。因为是可变类型,该变量的初始值为nil:
 
var john: Customer?

 现在创建一个Customer实例,然后用它来初始化CreditCard实例,并把刚创建出来的CreditCard实例赋值给Customer的card属性:

john = Customer(name: "John Appleseed") john!.card = CreditCard(number: 1234_5678_9012_3456, customer:john!)

 此时的引用关系如下图所示

因为john对CreditCard实例是非持有引用,当破坏john变量持有的强引用时,就没有Customer实例的强引用了

此时Customer实例被销毁。然后,CreditCard实例的强引用也不复存在,因此CreditCard实例也被销毁

john = nil // 打印"John Appleseed is being deinitialized" // 打印"Card #1234567890123456 is being deinitialized"

  

  非持有引用以及隐式展开的可选属性

Person和Apartment的例子说明了下面的场景:两个属性的值都可能是nil,并有可能产生强引用环。这种场景下适合使用弱引用。
 
Customer和CreditCard的例子则说明了另外的场景:一个属性可以是nil,另外一个属性不允许是nil,并有可能产生强引用环。这种场景下适合使用无主引用。
 
但是,存在第三种场景:两个属性都必须有值,且初始化完成后不能为nil。这种场景下,则要一个类用无主引用属性,另一个类用隐式展开的可选属性。这样,在初始化完成后我们可以立即访问这两个变量(而不需要可选展开)

 下面的例子定义了两个类,Country和City,都有一个属性用来保存另外的类的实例。在这个模型里,每个国家都有首都,每个城市都隶属于一个国家。所以,类Country有一个capitalCity属性,类City有一个co

首页 上一页 1 2 3 4 下一页 尾页 2/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇[转]setValue和setObject的区别 下一篇【代码笔记】iOS-评分系统(小星..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目