Swift内存管理:

Swift 和 OC 用的都是ARC的内存管理机制,它们通过 ARC 可以很好的管理对象的回收,大部分的时候,程序猿无需关心 Swift 对象的回收。

注意:

只有引用类型变量所引用的对象才需要使用引用计数器进行管理,对于枚举、结构体等,他们都是值类型的。因此不需要使用引用计数进行管理。

一:理解ARC

1: ARC 自动统计改对象被多少引用变量引用,这个值就是我们常说的引用计数器。

2: 每当引用计数器计数变为0的时候,ARC就会回收这个对象。

比如,现在我们做一个针对大学生用户的APP,我们写了一个User类,这个类里面有姓名、年纪、班级三个属性,看整个文件代码:

  1. import UIKit
  2. class ComNavigationController: UINavigationController {
  3.  
  4. class User {
  5.  
  6. var name:String
  7. var age:Int
  8. var classes:String
  9. init(name:String,age:Int,classes:String)
  10. {
  11. self.name = name
  12. self.age = age
  13. self.classes = classes
  14. }
  15.  
  16. deinit{
  17. print("\(self.name) 用户即将被销毁")
  18. }
  19. }
  20. override func viewDidLoad() {
  21.  
  22. var user1:User?
  23. user1 = User(name:"zhangxu",age:24,classes:"三年二班")
  24. /// 创建了一个User对象 用户1这个变量是指向User对象的,这时候User对象的引用计数为1
  25.  
  26. var user2:User?
  27. user2 = user1
  28.  
  29. var user3:User?
  30. user3 = user1
  31. // 这时候被变量2 和变量3 都引用了,User对象的引用计数就变成了------ 3
  32.  
  33. print(user2)
  34. print(user3)
  35.  
  36. user1 = nil
  37. user2 = nil
  38. user3 = nil
  39. // 1 2 3 都置为你了 用户都不再引用User对象
  40. // 这时候 User对象不被任何变量引用,引用计数器就变成了0
  41. // 引用计数器编程了 0 ,ARC就会回收该对象
  42.  
  43. super.viewDidLoad()
  44. // Do any additional setup after loading the view.
  45. }
  46.  
  47. override func didReceiveMemoryWarning() {
  48. super.didReceiveMemoryWarning()
  49. // Dispose of any resources that can be recreated.
  50. }
  51. /*
  52. // MARK: - Navigation
  53.  
  54. // In a storyboard-based application, you will often want to do a little preparation before navigation
  55. override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
  56. // Get the new view controller using segue.destinationViewController.
  57. // Pass the selected object to the new view controller.
  58. }
  59. */
  60. }

              

二:强引用循环

大部分时候,ARC能够很好的处理程序中对象的内存回收,但如果这两个对象之间存在着相互的引用,也就是当两个对象都使用存储属性相互的引用对方的时候,此时两个对象的引用计数都等于 1 ,但实际上它们都没有被真正的引用变量所引用,就像上面的 user1 这样的变量。这时候的 ARC是无法回收它们的。

看下面的代码示例:

  1. class teacher {
  2.  
  3. var name:String
  4. var age:Int
  5. var student1:student?
  6.  
  7. init(name:String,age:Int)
  8. {
  9. self.name = name
  10. self.age = age
  11. }
  12. deinit{
  13.  
  14. print("老师对象被回收");
  15. }
  16.  
  17. }
  18.  
  19. class student {
  20.  
  21. var name:String
  22. var age:Int
  23. var teacher1:teacher?
  24. init(name:String,age:Int)
  25. {
  26. self.name = name
  27. self.age = age
  28. }
  29. deinit{
  30.  
  31. print("老师对象被回收");
  32. }
  33.  
  34. }
  35.  
  36. var stu:student? = student(name: "zhangxiaxu",age: 24)
  37. var tea:teacher? = teacher(name: "wangnima",age: 200)
  38.  
  39. // 就在这里相互引用,形成了强引用循环
  40. stu?.teacher1 = tea
  41. tea?.student1 = stu
  42.  
  43. stu = nil
  44. tea = nil

解释一下:

上面的代码执行完之后,两个对象之间不再有真正的引用变量引用他们,但两个对象之间的相互引用,形成了"强引用循环",此时它们的引用计数为 1 ,ARC也不会去回收它们,任何一个对象释放,都要等对方先释放,因此两个对象只爱你谁都没办法被回收,这两个对象在这时候就变成了垃圾。为了结局上面的强引用循环,我们就必须让一方先放手,允许对方先释放。Swift这时候提供了两种机制: 弱引用和无主引用

三:使用弱引用解决强引用循环

弱引用不会增加对方的引用计数,因此不会阻止ARC回收被引用的实例,这样就避免了形成强引用循环, 在定义属性的 var 关键字之前加 weak 就定义了弱引用。

注意点:

1 : 弱引用变量要求该变量必须要能被设置成 nil ,也就是弱引用的属性最好是使用可选类型来定义。

2 : 弱引用的属性只能声明为变量类型,因为该属性在运行期内只有可能会发生变化,因此不能设置成常量。

3 :也没必要把两个相互引用的属性都设置成弱引用,有一个就可以了。

所以,要是使用弱引用解决上面的强引用循环的,只需按下面声明属性:

  1. // 修改teacher类的 student 为弱引用属性
  2. weak var student1:student?
  3.  
  4. // 或者修改 student 类的 teacher 为弱引用属性
  5. weak var teacher1:teacher?

四:使用无主引用解决强引用循环

与弱引用相似的是,无主引用也不会增加对方的引用计数,无主引用于弱引用的区别:

无主引用不允许接受nil,意思就是这个属性要一直有值!因此无主引用只能定义为非可选类型。

在定义属性 var 或者 let 之前,添加 unowned 关键字即可。上面的强引用要用无主引用解决的话,看下面代码:

  1. // 声明 teacher 类的 student 属性为无主引用 且 不能是可选类型。
  2. unowned let student1:student
  3.  
  4. // 或者声明 student 类的 teacher 属性为无主引用
  5. unowned let teacher1:teacher

五:闭包的强引用循环解决

上面给出了两种方式,说说他们的使用场景的一个区别。

当闭包和捕获的对象总是相互引用,并且总是同事销毁时,应该将闭包内捕获的实例定义为无主引用。

当闭包捕获的引用变量有可能是 nil 时,将闭包捕获的引用变量定义为弱引用。

如果程序将该对象本身传入了闭包,那么闭包本身就会捕获该对象,于是该对象就持有了闭包属性,反过来,闭包也持有对象,这样子就形成了强引用。

  1. import UIKit
  2. class ComNavigationController: UINavigationController {
  3.  
  4. class teacher {
  5.  
  6. var name:String
  7. var age:Int
  8.  
  9. lazy var findteacher:() ->String = {
  10.  
  11. [unowned self] in
  12. return "该老师名字是\(self.name) 年纪是\(self.age)"
  13.  
  14. //[weak self] in
  15. //return "该老师名字是\(self!.name) 年纪是\(self!.age)"
  16. }
  17.  
  18. init(name:String,age:Int)
  19. {
  20. self.name = name
  21. self.age = age
  22. }
  23.  
  24. deinit{
  25.  
  26. print("老师对象被回收");
  27. }
  28. }
  29.  
  30. override func viewDidLoad() {
  31.  
  32. super.viewDidLoad()
  33.  
  34. var tea:teacher? = teacher(name: "葫芦娃",age: 24)
  35. var find:(() ->String)? = tea!.findteacher
  36.  
  37. tea = nil
  38. find = nil
  39.  
  40. // Do any additional setup after loading the view.
  41. }
  42. override func didReceiveMemoryWarning() {
  43. super.didReceiveMemoryWarning()
  44. // Dispose of any resources that can be recreated.
  45. }
  46. }

解释一下:

上面代码中,我们看在 viewdidload 方法中,先创建了一个 teacher 对象,并且赋值给 tea 变量,接下来有定义了一个函数类型的变量,并且将 teacher 实例的 findteacher 属性赋值给该变量,到后面tea 和 find 变量都赋值为 nil , 此时没有引用变量引用 teacher 对象和闭包对象,但两个对象之间的相互引用就形成了强引用循环。

当然,我们只是说形成了,上面的代码里面也已经给出了解决的方法,尤其注意一点,就是使用无主引用和弱引用时候 self 的区别。

Swift 内存管理详解的更多相关文章

  1. Apache Spark 内存管理详解(转载)

    Spark 作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色.理解 Spark 内存管理的基本原理,有助于更好地开发 Spark 应用程序和进行性能调优.本文旨在梳理出 ...

  2. 动态内存管理详解:malloc/free/new/delete/brk/mmap

    c++ 内存获取和释放 new/delete,new[]/delete[] c 内存获取和释放 malloc/free, calloc/realloc 上述8个函数/操作符是c/c++语言里常用来做动 ...

  3. spark内存管理详解

    Spark 作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色.理解 Spark 内存管理的基本原理,有助于更好地开发 Spark 应用程序和进行性能调优.本文旨在梳理出 ...

  4. MemCache中的内存管理详解

    MC的内存管理机制 1.内存的碎片化 当我们使用C语言或者其他语言进行malloc(申请内存),free(释放内存)等类似的命令操作内存的时候, 在不断的申请和释放的过程中,形成了一些很小的内存片段, ...

  5. 转:C/C++内存管理详解 堆 栈

    http://chenqx.github.io/2014/09/25/Cpp-Memory-Management/ 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了 ...

  6. QF——OC内存管理详解

    堆的内存管理: 我们所说的内存管理,其实就是堆的内存管理.因为栈的内存会自动回收,堆的内存需要我们手动回收. 栈中一般存储的是基本数据类型变量和指向对象的指针(对象的引用),而真实的对象存储在堆中.因 ...

  7. Memcached 内存管理详解

    Memcached是一个高效的分布式内存cache,了解memcached的内存管理机制,便于我们理解memcached,让我们可以针对我们数据特点进行调优,让其更好的为我所用. 首先需要我们先了解两 ...

  8. IOS内存管理详解

    一.    基本原理 1.        什么是内存管理 移动设备的内存极其有限,每个app所能占用的内存是有限制的 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空 ...

  9. Apache Spark 内存管理详解

    在spark里面,内存管理有两块组成,一部分是JVM的堆内内存(on-heap memory),这部分内存是通过spark dirver参数executor-memory以及spark.executo ...

随机推荐

  1. ucos2.86的任务调度漏洞

    Ucos2.86版本有一个任务调度的漏洞,该漏洞在2.88之后的版本已经修改过来了,今天我们来看看这个漏洞, 漏洞在官方2.88的文档中如下 这两个函数都是调度器函数,也就是说调度器有漏洞,但是看官方 ...

  2. iOS 消息推送原理及实现总结

    在实现消息推送之前先提及几个于推送相关概念,如下图:1. Provider:就是为指定IOS设备应用程序提供Push的服务器,(如果IOS设备的应用程序是客户端的话,那么Provider可以理解为服务 ...

  3. Intent的概念及应用(一)

    ------siwuxie095 1.显式Intent (1)先创建一个项目:LearnIntent,选择API:21 Android 5.0, 选择Empty Activity,完成 (2)创建一个 ...

  4. Memcached源码分析

    作者:Calix,转载请注明出处:http://calixwu.com 最近研究了一下memcached的源码,在这里系统总结了一下笔记和理解,写了几 篇源码分析和大家分享,整个系列分为“结构篇”和“ ...

  5. java实现——004替换空格

    1.创建新的字符串 public class T004 { public static void main(String[] args){ System.out.println(replaceBlan ...

  6. 使用spol导出exce

    sqlplus 能生产xls的excel文件 connect / as sysdba; SET NEWPAGE 0 SET SPACE 0 SET LINESIZE 80 SET PAGESIZE 0 ...

  7. 3)Javascript设计模式:Observer模式

    Observer模式 var Observer = (function() { var instance = null; function Observe() { this.events = {} } ...

  8. 创业类网站建设日志1——搭建服务器svn以及前端开发环境

    1.需要在linux环境的服务器下搭建node和npm还有Grunt,所以先需要一个叫putty的工具连接服务器命令行终端 2.双击putty工具,在HostName一栏输入项目服务器地址:172.1 ...

  9. YII 1.0 设置关联模型

    在model中设置如下 /* * 设置关联 */ public function relations(){ return array( 'cate'=>array(self::BELONGS_T ...

  10. cf747 D. Winter Is Coming

    天呢,这个题2333333,真是被各种卡.完蛋完蛋完蛋.IQ------------: #include<bits/stdc++.h> #define lowbit(x) x&(- ...