Swift学习笔记十五
自动引用计数(Automatic Reference Counting)
和OC一样,Swift用自动引用计数机制来跟踪和管理你应用程序的内存,大多数情况下,你不需要考虑自己管理内存,Swift会自动帮你管理。当实例对象不再需要时,Swift会自动释放它使用的内存。但是,在有些情况下,ARC需要知道更多你代码之间的关系来帮助你管理内存,本章会描述那些情况并展示如何启用ARC来管理你应用程序的内存。
注意:引用计数只作用于类实例,结构体和枚举是值类型而非引用类型,并且不是以引用形式被存储和传递的。
每当你创建一个新的类实例对象,ARC为它分配一块内存用以存储比如实例类型、实例相关联的存储式属性的值等。当实例不再被需要时,ARC会销毁实例,释放其所占用的内存以供他用。如果实例已经被销毁,那么就不能再使用它或者访问它的属性、方法。为了确保还被需要的实例不被销毁,ARC追踪有多少属性、常量及变量引用到了一个类实例,只要还有至少一个引用指向实例,ARC就不会销毁它。这是通过“强引用”实现的,当你将一个实例赋值给一个常量或者变量、属性时,那个常量或者变量、属性会与实例之间建立一个“强引用”,之所以成为“强”,是因为这个引用会只要这个引用还存在,那么这个实例就不能被释放销毁。
“强引用”在带来便利的时候,会产生一个问题,就是“强引用循环”,比如实例A的某个属性引用了实例B,而实例B的某个属性又引用了A,那么即使其他任何变量都没有引用A和B,他们也各自被一个强引用持有,那么即便他们都不再被需要,它们也不会被销毁,这就造成了内存泄露。
为了解决个这个问题,可以使用“弱引用(weak reference)”和“不持有引用(unowned reference)”。它们可以使你在引用某个实例对象的时候不会持有它,这样实例在互相引用的时候就不会产生强引用循环。
当引用在其生命周期内的某个时刻可能会是nil的时候,使用“弱引用”,当你确定某个引用在其生命周期内都不可能是nil的时候,使用“不持有引用”。因为弱引用是允许没有值的,因此它只能被赋值给可选类型(optional type)。
“弱引用”只能赋值给变量,不能赋值给常量,这是为了表明在运行时其值可能会发生变化的,当弱引用指向的对象已经被销毁时,ARC将弱引用的值改为nil。比如:
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { println("\(name) is being deinitialized") }
} class Apartment {
let number: Int
init(number: Int) { self.number = number }
weak var tenant: Person? //这里通过weak前缀来声明弱引用变量属性
deinit { println("Apartment #\(number) is being deinitialized") }
}
“不持有引用”和“弱引用”类似,不过它确保永远有值,因此,它总是被赋值给非可选类型,在访问它的时候,也不需要像可选类型那样展开,而是直接访问。此外,当其指向的对象已经被释放时,ARC不能将“不持有引用”设为nil,因为非可选类型的变量不能被设置为nil。事实上,当你访问一个指向已经被销毁对象的不持有引用时,会触发一个运行时错误。
当把一个闭包赋值给一个实例对象的属性,而闭包内部又引用这个实例时(比如闭包体访问实例的属性值self.property或者访问实例的方法self.method),也会发生“强引用循环”,这是因为闭包和类一样,是引用类型的。Swift提供一种优雅的方式来打破这种“强引用循环”,比如:
class HTMLElement { let name: String
let text: String? lazy var asHTML: () -> String = {
if let text = self.text { //这里引用了实例对象的属性
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
} init(name: String, text: String? = nil) {
self.name = name
self.text = text
} deinit {
println("\(name) is being deinitialized")
} }
这里HTMLElement类定义了一个lazy属性asHTML,它的默认值是一个闭包,因为它是属性而不是方法,因此你可以用自定义的函数或者闭包来取代默认值,这里属性被标记为lazy,因为它不需要在一开始就被赋值,只有在需要的时候(即需要生成HTML代码),才会执行这个闭包。正因为它是lazy的属性,因此在闭包体内可以访问self,因为执行它的时候初始化已经完成了。
要解决闭包的强引用循环问题,需要用到“捕获列表”,在定义闭包的时候同时定义其捕获列表,这个列表定义了闭包体内捕获一个或多个引用类型时所遵循的规则。
捕获列表是用一堆中括号定义,其内部的项用逗号隔开,每一个项都是一个关键字(weak或unowned)与一个类实例引用(或者一个变量的定义)组成的对,将捕获列表放在其参数列表之前,如下:
lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
// closure body goes here
}
这样就解除了闭包和实例对象之间的强引用循环。
Swift学习笔记十五的更多相关文章
- Swift 学习笔记十五:扩展
扩展就是向一个已有的类.结构体或枚举类型加入新功能(functionality).扩展和 Objective-C 中的分类(categories)相似.(只是与Objective-C不同的是,Swif ...
- python3.4学习笔记(十五) 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)
python3.4学习笔记(十五) 字符串操作(string替换.删除.截取.复制.连接.比较.查找.包含.大小写转换.分割等) python print 不换行(在后面加上,end=''),prin ...
- (转载)西门子PLC学习笔记十五-(数据块及数据访问方式)
一.数据块 数据块是在S7 CPU的存储器中定义的,用户可以定义多了数据块,但是CPU对数据块数量及数据总量是有限制的. 数据块与临时数据不同,当逻辑块执行结束或数据块关闭,数据块中的数据是会保留住的 ...
- (C/C++学习笔记) 十五. 构造数据类型
十五. 构造数据类型 ● 构造数据类型概念 Structured data types 构造数据类型 结构体(structure), 联合体/共用体 (union), 枚举类型(enumeration ...
- Swift学习笔记十六:协议
Protocol(协议)用于统一方法和属性的名称,而不实现不论什么功能. 协议可以被类.枚举.结构体实现.满足协议要求的类,枚举,结构体被称为协议的遵循者. 遵循者须要提供协议指定的成员,如属性,方法 ...
- swift学习第十五天:闭包
闭包 闭包的介绍 闭包和OC中的block非常相似 OC中的block是匿名的函数 Swift中的闭包是一个特殊的函数 block和闭包都经常用于回调 注意:闭包和block一样,第一次使用时可能不习 ...
- MySQL学习笔记十五:优化(2)
一.数据库性能评测关键指标 1.IOPS:每秒处理的IO请求次数,这跟磁盘硬件相关,DBA不能左右,但推荐使用SSD. 2.QPS:每秒查询次数,可以使用show status或mysqladmin ...
- Swift学习笔记十四
Deinitialization 当类的实例对象即将要被释放时,会立即调用deinitializer,通过deinit关键字来定义deinitializer,和initializer一样,它也只存在于 ...
- Swift学习笔记十二
方法 方法就是和某种特定类型相关联的函数.类.结构体.枚举都可以定义实例方法和类型方法.类型方法和OC中的类方法类似. 结构体和枚举也可以定义方法是Swift与C/OC之间很大的一个区别,在OC中,只 ...
随机推荐
- hdu 3951(博弈规律)
题意:给定围成一个圈的硬币n枚,然后每次可以取出连续的1-k枚,谁取完最后一枚谁就获胜. 分析:对于第二个人当第一个人取完后,他可以取成对称的形式,所以第二个人必胜. 代码: #include< ...
- sessionFactory.getCurrentSession()的引出
当业务逻辑中需要开启事务执行,业务逻辑也要调用底层操作数据库的函数,那函数也要开启事务操作. 如果用sessionFactory.openSession()的话会引起处理不在同一个事务中,会造成出错. ...
- Delphi RxRichEdit高级操作
unit InsertRichEditUnit;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, For ...
- 性能测试之Windows常见性能计数器
性能计数器(counter)是描述服务器或操作系统性能的一些数据指标.计数器在性能测试中发挥着“监控和分析”的关键作用,尤其是在分析系统的可扩展性.进行性能瓶颈的定位时,对计数器的取值的分析非常关键. ...
- ChromePHP - Chrome浏览器下的PHP debug工具
一款 Chrome 下用来配合调试 PHP 的工具,看官方介绍应该和 FirePHP 有异曲同工的.喜欢用Chrome 的PHPer 可以尝试一下. 官方网站:http://www.chromephp ...
- Javascript 日期时间格式正则
因为Javascript的日期格式判断可能因浏览器的版本有所不同,所以用正则判断会比较好,这里备注一个正则用来判断日期时间的格式: ^(?=\d)(?:(?!(?:1582(?:\.|-|\/)10( ...
- hive 面试题 转载
转自:http://blog.csdn.net/ningguixin/article/details/12852051 有一张很大的表:TRLOG该表大概有2T左右TRLOG:CREATE TABLE ...
- 【LeetCode】111 - Minimum Depth of Binary Tree
Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shor ...
- 2014搜狗前端面经【B事业部】
本来就投了一份简历,后来又收到了个B事业部的面试电话,今天刚面完一面,总体感觉还是很基础的,其中一名面试官帅到不行啊!另一个也不差,真是幸胡...(sorry,跑题了...) 上来先做了份笔试题,超级 ...
- 初识MFC,WinForm,WPF,Q't
MFC和QT是C++中常见的GUI框架,而WinForm和WPF是C#中常用的框架,不过我们一般很少叫WinForm框架,可能直接叫图形控件类库更多点.反正只是个称呼罢了,爱咋叫就咋叫.另外WinFo ...