设为首页 加入收藏

TOP

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

  Swift使用自动引用计数(ARC)来跟踪并管理应用使用的内存。大部分情况下,这意味着在Swift语言中,内存管理"仍然工作",不需要自己去考虑内存管理的事情。当实例不再被使用时,ARC会自动释放这些类的实例所占用的内存。然而,在少数情况下,为了自动的管理内存空间,ARC需要了解关于你的代码片段之间关系的更多信息。本章描述了这些情况,并向大家展示如何打开ARC来管理应用的所有内存空间。

注意:引用计数只应用在类的实例。结构体(Structure)和枚举类型是值类型,并非引用类型,不是以引用的方式来存储和传递的。
 
   How ARC Works
  每次创建一个类的实例,ARC就会分配一个内存块,用来存储这个实例的相关信息。这个内存块保存着实例的类型,以及这个实例相关的属性的值。当实例不再被使用时,ARC释放这个实例使用的内存,使这块内存可作它用。这保证了类实例不再被使用时,它们不会占用内存空间。但是,如果ARC释放了仍在使用的实例,那么你就不能再访问这个实例的属性或者调用它的方法。如果你仍然试图访问这个实例,应用极有可能会崩溃。为了保证不会发生上述的情况,ARC跟踪与类的实例相关的属性、常量以及变量的数量。只要有一个有效的引用,ARC都不会释放这个实例。
 
  为了让这变成现实,只要你将一个类的实例赋值给一个属性或者常量或者变量,这个属性、常量或者变量就是这个实例的强引用(strong reference)。之所以称之为“强”引用,是因为它强持有这个实例,并且只要这个强引用还存在,就不能销毁实例。
 
下面的例子展示了ARC是如何工作的。本例定义了一个简单的类,类名是Person,并定义了一个名为name的常量属性
class Person { let name: String init(name: String) { self.name = name println("\(name) is being initialized") } deinit { println("\(name) is being deinitialized") } }

 

接下来的代码片段定义了三个Person?类型的变量,这些变量用来创建多个引用,这些引用都引用紧跟着的代码所创建的Person对象。因为这些变量都是可选类型(Person?,而非Person),因此他们都被自动初始化为nil,并且当前并没有引用一个Person的实例。
var reference1: Person? 
var reference2: Person? 
var reference3: Person? 

 现在我们创建一个新的Person实例,并且将它赋值给上述三个变量中的一个:

reference1 = Person(name: "John Appleseed") // prints "Jonh Appleseed is being initialized" 
因为Person的实例赋值给了变量reference1,所以reference1是Person实例的强引用。又因为至少有这一个强引用,ARC就保证这个实例会保存在内存重而不会被销毁。
 
如果将这个Person实例赋值给另外的两个变量,那么将建立另外两个指向这个实例的强引用:
reference2 = reference1 reference3 = reference2 

 

现在,这一个Person实例有三个强引用。
 
如果你通过赋值nil给两个变量来破坏其中的两个强引用(包括原始的引用),只剩下一个强引用,这个Person实例也不会被销毁:

 

reference1 = nil reference2 = nil 

直到第三个也是最后一个强引用被破坏,ARC才会销毁Person的实例,这时,有一点非常明确,你无法继续使用Person实例:

referenece3 = nil // 打印 “John Appleseed is being deinitialized” 

 

                                         

   类实例之间的强引用循环 
 
 在两个类实例彼此保持对方的强引用,使得每个实例都使对方保持有效时会发生这种情况。我们称之为强引用循环。
 下面的例子展示了一个强引用环是如何在不经意之间产生的。例子定义了两个类,分别叫Person和Apartment,这两个类建模了一座公寓以及它的居民:
 
 
class Person { let name: String init(name: String) { self.name = name } var apartment: Apartment? deinit { println("\(name) is being deinitialized") } } class Apartment { let unit: Int init(unit: Int) { self.unit= unit } var tenant: Person? deinit { println("Apartment #\(number) is being deinitialized") } } 

 

每个Person实例拥有一个String类型的name属性以及一个被初始化为nil的apartment可选属性。apartment属性是可选的,因为一个人并不一定拥有一座公寓。
 
类似的,每个Apartment实例拥有一个Int类型的number属性以及一个初始化为nil的tenant可选属性。tenant属性是可选的,因为一个公寓并不一定有居民。
 
这两个类也都定义了初始化函数,打印消息表明这个类的实例正在被初始化。这使你能够看到Person和Apartment的实例是否像预期的那样被销毁了。
 
下面的代码片段定义了两个可选类型变量,john和number73,分别被赋值为特定的Apartment和Person的实例。得益于可选类型的优点,这两个变量初始值均为nil:
 
var john: Person? 
var unit4A: Apartment?

 现在,你可以创建特定的Person实例以及Apartment实例,并赋值给john和number73:

jhon = Person(name: "John Appleseed") unit4A = Apartments(number: 4A) 

 下面的图表明了在创建以及赋值这两个实例后强引用的关系。john拥有一个Person实例的强引用,unit4A拥有一个Apartment实例的强引用:

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

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目