Swift内存管理、weak和unowned以及两者区别(如何使用Swift 中的weak与unowned?)
Swift 是自动管理内存的,这也就是说,我们不再需要操心内存的申请和分配。
当我们通过初始化创建一个对象时,Swift 会替我们管理和分配内存。而释放的原则遵循了自动引用计数 (ARC) 的规则:当一个对象没有引用的时候,其内存将会被自动回收。
这套机制从很大程度上简化了我们的编码,我们只需要保证在合适的时候将引用置空 (比如超过作用域,或者手动设为 nil
等),就可以确保内存使用不出现问题。
但是,所有的自动引用计数机制都有一个从理论上无法绕过的限制,那就是循环引用 (retain cycle) 的情况。
什么是循环引用
假设我们有两个类 A
和 B
, 它们之中分别有一个存储属性持有对方:
class A {
let b: B
init() {
b = B()
b.a = self
}
deinit {
println("A deinit")
}
}
class B {
var a: A? = nil
deinit {
println("B deinit")
}
}
在 A
的初始化方法中,我们生成了一个 B
的实例并将其存储在属性中。然后我们又将 A
的实例赋值给了 b.a
。这样 a.b
和 b.a
将在初始化的时候形成一个引用循环。现在当有第三方的调用初始化了 A
,然后即使立即将其释放, A
和 B
两个类实例的 deinit
方法也不会被调用,说明它们并没有被释放。
因为即使 obj
不再持有 A
的这个对象,b 中的 b.a
依然引用着这个对象,导致它无法释放。而进一步,a 中也持有着 b,导致 b 也无法释放。在将 obj
设为 nil
之后,我们在代码里再也拿不到对于这个对象的引用了,所以除非是杀掉整个进程,我们已经 永远 也无法将它释放了。多么悲伤的故事啊..
在 Swift 里防止循环引用
为了防止这种人神共愤的悲剧的发生,我们必须给编译器一点提示,表明我们不希望它们互相持有。一般来说我们习惯希望 "被动" 的一方不要去持有 "主动" 的一方。在这里 b.a 里对 A 的实例的持有是由 A 的方法设定的,我们在之后直接使用的也是 A 的实例,因此认为 b 是被动的一方。可以将上面的 class B
的声明改为:
class B {
weak var a: A? = nil
deinit {
println("B deinit")
}
}
在 var a
前面加上了 weak
,向编译器说明我们不希望持有 a。这时,当 obj
指向 nil
时,整个环境中就没有对 A
的这个实例的持有了,于是这个实例可以得到释放。接着,这个被释放的实例上对 b 的引用 a.b
也随着这次释放结束了作用域,所以 b
的引用也将归零,得到释放。添加 weak
后的输出:
A deinit
B deinit
weak和unowned
在 Swift 中除了 weak
以外,还有另一个冲着编译器叫喊着类似的 "不要引用我" 的标识符,那就是 unowned
。它们的区别在哪里呢?如果您是一直写 Objective-C 过来的,那么从表面的行为上来说 unowned
更像以前的 unsafe_unretained
,而 weak
就是以前的 weak
。
用通俗的话说,就是 unowned
设置以后即使它原来引用的内容已经被释放了,它仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil
。如果你尝试调用这个引用的方法或者访问成员属性的话,程序就会崩溃。而 weak
则友好一些,在引用的内容被释放后,标记为 weak
的成员将会自动地变成 nil
(因此被标记为 @ weak
的变量一定需要是 Optional 值)。
关于两者使用的选择,Apple 给我们的建议是如果能够确定在访问时不会已被释放的话,尽量使用 unowned
,如果存在被释放的可能,那就选择用 weak
。
日常工作中一般使用弱引用的最常见的场景有两个:
- 设置
delegate
时 - 在
self
属性存储为闭包时,其中拥有对self
引用时
其中,最常见的delegate使用时,可参考我这篇文章:
Swift代理造成内存泄漏的解决办法
所以,weak使用上是更推荐一点的。
Swift内存管理、weak和unowned以及两者区别(如何使用Swift 中的weak与unowned?)的更多相关文章
- Swift 内存管理详解
Swift内存管理: Swift 和 OC 用的都是ARC的内存管理机制,它们通过 ARC 可以很好的管理对象的回收,大部分的时候,程序猿无需关心 Swift 对象的回收. 注意: 只有引用类型变量所 ...
- swift内存管理中的引用计数
在swift中,每一个对象都有生命周期,当生命周期结束会调用deinit()函数进行释放内存空间. 观察这一段代码: class Person{ var name: String var pet: P ...
- Swift内存管理、weak和unowned以及两者区别
Swift 是自动管理内存的,这也就是说,我们不再需要操心内存的申请和分配.当我们通过初始化创建一个对象时,Swift 会替我们管理和分配内存.而释放的原则遵循了自动引用计数 (ARC) 的规则:当一 ...
- swift 内存管理,WEAK 和 UNOWNED
因为 Playground 本身会持有所有声明在其中的东西,因此本节中的示例代码需要在 Xcode 项目环境中运行.在 Playground 中可能无法得到正确的结果. 不管在什么语言里,内存管理的内 ...
- Swift 内存管理
1.Object-C 经历两个阶段: 1.手动引用计数内存管理(Manual Reference Counting,MRC) 2.自动引用计数内存管理(Automatic Refernce Count ...
- Swift内存管理-示例讲解
具体而言,Swift中的ARC内存管理是对引用类型的管理,即对类所创建的对象采用ARC管理.而对于值类型,如整型.浮点型.布尔型.字符串.元组.集合.枚举和结构体等,是由处理器自动管理的,程序员不需要 ...
- swift内存管理
为了解决引用循环的问题. However, with ARC, values are deallocated as soon as their last strong reference is rem ...
- swift内存管理:值类型与引用类型
Use struct to create a structure. Structures support many of the same behaviors as classes, includin ...
- iOS内存管理布局及管理方案-理论篇
苹果设备备受欢迎的背后离不开iOS优秀的内存管理机制,那iOS的内存布局及管理方案是怎样的呢?我们一起研究下. 内存管理分为五大块 栈区(stack):线性结构,内存连续,系统自己管理内存,程序运行记 ...
随机推荐
- 使用 DES 算法对数据加密
DES算法 ☆提供高质量的数据保护,防止数据未经授权的泄露和未被察觉的修改 ☆具有相当高的复杂性,使得破译的开销超过可能获得的利益,同时又要便于理解和掌握 ☆DES密码体制的安全性应该不依赖于算法的保 ...
- ConcurrentHashMap之实现细节
ConcurrentHashMap是Java 5中支持高并发.高吞吐量的线程安全HashMap实现.在这之前我对ConcurrentHashMap只有一些肤浅的理解,仅知道它采用了多个锁,大概也足够了 ...
- [Android] Anreoid repo 切换分支
reference : http://blog.csdn.net/lihui130135/article/details/40858885 如果已经有android仓库但是还不是最新的,想切换到And ...
- tsort - 拓扑排序
tsort - 拓扑排序 本文链接:http://codingstandards.iteye.com/blog/834572 (转载请注明出处) 用途说明 tsort命令通常用于解决一种逻辑问题, ...
- Git 学习(六)分支管理
Git 学习(六)分支管理 几乎每一种版本控制系统都支持分支.使用分支意味着你可以从开发主线上分离开来,然后不影响主线的同时继续工作.在很多版本控制系统中,这是个昂贵的过程,常常需要创建一个源代码目录 ...
- BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第14章节--使用Office Services开发应用程序 总结
BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第14章节--使用Office Services开发应用程序 总结 SP2013新的server端Off ...
- iOS:NSBundle的具体介绍
NSBundle介绍:它是一个单例类,用来加载资源 bundle是一个目录,其中包含了程序会使用到的资源. 这些资源包含了如图像,声音,编译好的代码,nib文件(用户也会把bundle称为plug-i ...
- Objective-C:动态绑定
// Complex.h // 03-动态绑定 // // Created by ma c on 15/8/11. // Copyright (c) 2015年. All rights reserve ...
- 第八章 ArrayBlockingQueue源码解析
注意:在阅读本文之前或在阅读的过程中,需要用到ReentrantLock,内容见<第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()><第六章 Reen ...
- 网站日志访问记录组件UserVisitLogsHelp开源了!
之前在<一种基于自定义代码记录用户访问日志在Sharepoint网站的应用方法!>一文利用本人几年前的开发的UserVisitLogsHelp组件进行了网站用户访问日志记录,可用于网站分析 ...