swift 4.2 官方文档学习笔记(十六)- Automatic Reference Counting

ARC automatically frees up the memory used by class instances when those instances are no longer needed.

In a few cases ARC requires more information about the relationships between parts of your code in order to manage memory for you.

Reference counting applies only to instances of classes.(不讨论struct和enum)

看完这章,要能回答一下几个问题:

  1. 什么是ARC?
  2. ARC是如何工作的
  3. strong reference cycle是怎么形成的?在工作中哪些情况是strong reference cycle?
  4. 如何解决strong reference cycle的问题
  5. strong reference cycles for closures

ARC是如何工作的

Every time you create a new instance of a class, ARC allocates a chunk of memory to store information about that instance.

when an instance is no longer needed, ARC frees up the memory used by that instance so that the memory can be used for other purposes instead.

To make sure that instances don’t disappear while they are still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists.(计数strong reference避免不和时机的释放)

strong reference cycle是怎么形成的?在工作中哪些情况是strong reference cycle?

简单来说就是两个不同的instance,有强指针指向对方,使对方始终不能ARC清零释放

工作当中常见的就比如,某个菜谱包含N个task,每个 task也会记录自己属于哪个菜谱,这样双方都包含对方参数内容的例子就是strong reference cycle

如何打破strong reference cycle

使用weak或者unowned关键词来打破这个cycle,但两者的使用环境有区别,先来看怎么使用weak:

这个例子中,apartment property可以是nil,因为对于一个人来说,他有可能没有房子,apartment的tenant参数也可能是nil,因为房子有可能没人住,这种互相关联不大的情况就可以用weak,当Person = nil时,Apartment一方的对应参数被设置为nil。需要注意的是只在一个class中加了weak,所以直接释放Apartment实例时还是不行,因为person还有强引用。

再来看看怎么使用unowned:

先来解释为什么在这里使用onowned而不是weak,这个例子里面使用weak就是错误的,因为对于信用卡来说,他必须有个主人(customer),不知道有没有注意到这里两个class互相指向的参数和上一个例子的区别?对,这两个参数其中有一个不是optional的,而这个不是optional的参数关键词只能使用unowned,因为当两个实例都被生成时,如果customer = nil,creditcard也会马上变为nil,他在检测他必须的参数customer是否存在,一旦不存在就会释放自己。所以总结来说,unowned就是说,我在检测这个必须不为空property。

Strong Reference Cycles for Closures

在某些class中,会包含一些function带有closure,而且这个closure引用了本身的self.XXX,引用了自己的参数,造成了strong reference,只要是这个class类型的实例,生成后都不能被释放,这个是很讨厌的。那么怎么去解决这个问题呢?

使用capture list来解决这个问题,顾名思义,就是建立一个捕获列表,捕获有可能是strong reference的参数,把他们一个一个的设置:

来看看weak 和unowned关键词在这里的区别:

Define a capture in a closure as an unowned reference when the closure and the instance it captures will always refer to each other, and will always be deallocated at the same time.
Conversely, define a capture as a weak reference when the captured reference may become nil at some point in the future. Weak references are always of an optional type, and automatically become nil when the instance they reference is deallocated. This enables you to check for their existence within the closure’s body.

这两个例子意思差不多,书写格式不太一样,使用这个来修饰的参数就不会形成强指针,实例随时可以被释放。一般self一定要声明为unowned的,因为self都不存在了,这个instance没有存在的意义一定会被释放。而其他参数比如delegate,如果是optional的property,就可以标成weak,当delegate指向的实例被释放的时候,self实例的存在不会受到影响,只是delegate = nil

最后,我们讨论完了weak和unowned使用条件,这里还可能有一种情况,就是没有任何一个property的值可以被设置成nil,这时候只能使用unowned,不过具体的远离我没有很明白,先记在这里,回头再理解一下:

Unowned References and Implicitly Unwrapped Optional Properties