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 。

日常工作中一般使用弱引用的最常见的场景有两个:

  1. 设置 delegate 时
  2. 在 self 属性存储为闭包时,其中拥有对 self 引用时

其中,最常见的delegate使用时,可参考我这篇文章:

Swift代理造成内存泄漏的解决办法

所以,weak使用上是更推荐一点的。

Swift内存管理、weak和unowned以及两者区别的更多相关文章

  1. Swift 内存管理详解

    Swift内存管理: Swift 和 OC 用的都是ARC的内存管理机制,它们通过 ARC 可以很好的管理对象的回收,大部分的时候,程序猿无需关心 Swift 对象的回收. 注意: 只有引用类型变量所 ...

  2. swift内存管理中的引用计数

    在swift中,每一个对象都有生命周期,当生命周期结束会调用deinit()函数进行释放内存空间. 观察这一段代码: class Person{ var name: String var pet: P ...

  3. swift 内存管理,WEAK 和 UNOWNED

    因为 Playground 本身会持有所有声明在其中的东西,因此本节中的示例代码需要在 Xcode 项目环境中运行.在 Playground 中可能无法得到正确的结果. 不管在什么语言里,内存管理的内 ...

  4. Swift内存管理、weak和unowned以及两者区别(如何使用Swift 中的weak与unowned?)

    Swift 是自动管理内存的,这也就是说,我们不再需要操心内存的申请和分配. 当我们通过初始化创建一个对象时,Swift 会替我们管理和分配内存.而释放的原则遵循了自动引用计数 (ARC) 的规则:当 ...

  5. Swift 内存管理

    1.Object-C 经历两个阶段: 1.手动引用计数内存管理(Manual Reference Counting,MRC) 2.自动引用计数内存管理(Automatic Refernce Count ...

  6. Swift内存管理-示例讲解

    具体而言,Swift中的ARC内存管理是对引用类型的管理,即对类所创建的对象采用ARC管理.而对于值类型,如整型.浮点型.布尔型.字符串.元组.集合.枚举和结构体等,是由处理器自动管理的,程序员不需要 ...

  7. swift内存管理

    为了解决引用循环的问题. However, with ARC, values are deallocated as soon as their last strong reference is rem ...

  8. swift内存管理:值类型与引用类型

    Use struct to create a structure. Structures support many of the same behaviors as classes, includin ...

  9. Swift中的Weak Strong Dance

    亲爱的博客园的关注着博主文章的朋友们告诉你们一个很不幸的消息哦, 这篇文章将会是博主在博客园发表的最后一篇文章咯, 因为之后的文章博主只会发布到这里哦 http://daiweilai.github. ...

随机推荐

  1. [moka同学笔记]MySql语句整理

    更改单个表中的字段属性 content 以前为text类型的,现在改为longtext ALTER TABLE `notice` CHANGE `content` `content` LONGTEXT ...

  2. Android 4.0.3 CTS 测试

    Android-CTS 4.0.3测试基本配置 1. Download CTS CTS的获取方式有两种: 1.1.由Google提供 1.1.1.打开浏览器输入连接: http://source.an ...

  3. Java的整个字符串的结束索引在最后一个字符之外

    /** * Created by xfyou on 2016/11/4. */ public class SubstringDemo { public static void main(String[ ...

  4. linux非常用但很有用的命令

    查找指定目录下包含指定字符串的所有文件 grep -rl 'abc' / top查看命令的完整启动路径 top 按c top以MB为单位显示内存信息 top -M 查看内存top io趋势 pidst ...

  5. 【转载】GUID vs INT Debate

    I recently read a blog post on what was better using GUIDs or Integer values. This is been an age lo ...

  6. pdo mysql错误:Cannot execute queries while other unbuffered queries are active

    运行环境:PHP 5.5.30-x64,MYSQL  5.6.27 错误代码:Cannot execute queries while other unbuffered queries are act ...

  7. 浅谈float浮动

    float大概是css3以前网页布局里最常用的一个属性了,经常看到一言不合就浮动的代码,就一起来深入挖掘一下这个一半天使一半魔鬼的属性吧. 本文是读张鑫旭大神慕课网float视频后的一些总结及一些拓展 ...

  8. 探究TCP

    OSI OSI是Open System Interconnection的缩写,意为开放式系统互联.国际标准化组织(ISO)制定了OSI模型,该模型定义了不同计算机互联的标准,是设计和描述计算机网络通信 ...

  9. 移动web开发介绍——浏览器

    前段时间了解学习了一下<移动Web手册>,觉得真的需要这种不是偏向技术.框架或工具的书籍,只是单纯的讲解一些关于移动Web最基本的知识.正好今天整理一部分之前学习过的内容,记录和分享,也方 ...

  10. 如何在Infraworks中创建多树种组成的森林

    在Infraworks 2014中,你可以有shp文件导入生成树木和森林,也可以直接在模型中规划一片区域作为森林.美中不足的就是,这些充其量叫树林不能叫森林,因为他们的样式都是一个树种,而真正的森林肯 ...