# Day16--ARC到底是虾饺?神秘的实体化背後的秘密

当一个类别实体被指派值(给一个属性、常数或变数)的时候,会建立一个该实体的强参考(strong reference),同时会将参考计数(reference counting)加 1 ,强参考表示会将这个实体保留住,只要强参考还在(也就是参考计数不为 0 ),储存这个实体的记忆体就不会被释放掉。

这是什麽意思呢?

简言之,就是当你举了一实体的例子,你就会建立了一个这个实体的强参考,也会在自动计数里加1,而强参考就会在你举的这个实体里存在,而只要强参考的内容还在,这个记忆体就不会不见。

就以上例来说,ARC的作用就是在你将一个变数明显的指向某一个“有值”的内容的时候,ARC就会自动加1。

而如若指向nil,变数的状态就会让参考计数变低,多一个nil值,也就少一个参考计数。

类别实体间的强参考循环

ARC 在大部分时间都可以运作顺利,但在有些情况下会造成强参考永远不会归零,进而发生记忆体泄漏(memory leak)的问题。

以下的例子是两个类别彼此都拥有对方强参考的属性,一个实体要释放记忆体前,必须先释放对方强参考,而对方要释放前也是要原本实体先释放,进而产生强参考循环。

就以上述例子来说,其实最重要的是从18行到21行的位置,18–19行我们把变数分别指向了对方,然後在21–22行的位置,我们把他们两个都指向了空值,但是这个时候ARC在运作的时候,因为各有一方指向对方的强参考,就算我们表面上看不出来,强参考的值就会是2,而没办法解开。
也因为强参考循环的情形是可能会造成在编写程序的时候,产生困扰,因此,Swift为了解决强参考循环的问题,因此有两个解决方案:

  1. 弱参考(weak reference)
  2. 无主参考(unowned reference)

这两种参考也能参考实体,但因为不是强参考,所以不会保留住实体的参考(也就是这个实体的参考计数不会增加)。
而两者的差别在於,如果一个参考这个实体的变数在生命周期中,可能会为nil时,就使用弱参考,而在初始化之後不会再变为nil的则是使用无主参考。

为求理解,我们以实例来探讨:

弱参考

在上述此例中,我们应该先抓到关键字:weak var tenant:Person?也就是说,现在tenant这个变数现在是一个弱参考。

那再往下看,我们可以知道,joe2承载着类别Person的内容,而oneUnit2承载着类别Apartment的内容,而oneUnit2里面有一个弱参考的变数。

而接着是Joe2强力解包,将住屋情况指为oneUnit2,但oneUnit2是弱参考,所以不会增加joe2的参考计数,
oneUnit2强力解包,将内容指为joe2。这个时候joe2内含弱参考的变数,尚且不会增加计数。

接着,将两者都分别指向nil,断开强参考,於是,joe2的实体参考会减为0,而实体的弱参考则为nil,joe2被释放後,oneUnit2的实体减为1,接着oneUnit2断开强参考指派为nil,参考计数为0。

综合实例所及,弱参考的关键字带入後,即会为强参考的循环的问题找到出路,而原理则是被注为弱参考的变数不被计数所计,所以可以将让另一个受制为强参考的变数变为0

无主参考

与弱参考一样,无主参考(unowned reference)不会保留住参考的实体(所以这个实体的参考计数不会增加),但不同的是,无主参考会被视为永远有值,所以需要被定义为非可选型别,而因此可以直接存取,不需要强制解析(即加上惊叹号!)。

总之,在这里要注意的是无主参考被设定後,如第10行,且尚无需注明型别,实际作用的时候,则在第17行,jess!.card强力解包後,里面的参数customer给定jess,注明惊叹号,这个时候非可选型别的注记让jess不管怎麽样都可以使用。

这个时候,具有实体的是jess,它具有一个实体,因为我们给定了name:”jess”,参考计数为1

而jess.card也有计数,我们给定number:12345678,所以它也有一个计数,但CreditCard的计数为无主参考,所以没有计数。

总之,jess如果等於nil值,也就意味着CreditCard的强参考断开,因而释放。

稍微回顾一下这篇在描述的内容:
当一个类别实体被指派值(给一个属性、常数或变数)的时候,会建立一个该实体的强参考(strong reference),同时会将参考计数(reference counting)加 1。

也就是说,只要在类别Class里面,有一个指派值的时候,无论是常数、变数,都会建立一个强参考,同时会让参考计数+1。
所以,也就是要留意,属性、常数、变数在类别里面的成立与否。

就此,我们在这篇的内容里导引出一个结论,就是正常情况下,我们是可以将参考计数归零的(也就是全部都断开强参考,让实体指向nil)。

But!偏偏就是有一种情况:叫做强参考循环,它会让两个属性都是可选类型的情况,在赋值之後,各有参考计数,但因为需要,而让对方的属性内容成为对方的实体,这种情形,最後要将两个参考计数指为nil的时候,会没辨法让参考计数归零。
於是,便延伸出两种排除强参考循环的方式,叫做弱参考、无主参考。

弱参考的作法是让其中一个属性被赋予弱参考的性质,让它变得可以不被参考计数,於是两实体就算互指对方的属性,弱参考也可以因为它的特性,使被置名为弱参考的属性不计参考计数,而跳脱强参考循环,让参考计数能归零,记忆体被释放。

而无主参考的作法则是不会保留参考的实体,但却会永远有值,总之,它在实际上是不会被计算到参考计算的,所以被宣布为无主参考的属性,严格来说不算是一个“有值”的属性,但它对於Swift来说,就是一个“有值”的状态,所以,也因为这样,它得以绕过ARC针对类别里面的属性、变数、常数进行的计算。

如此,无主参考的原理就是利用它本身“永远有值“,却“不会保留实体”的特性,来绕过ARC的运作规则。

所以,无主参考的使用下,强参考循环也因此不受制於两边的属性都互相指名对方是对方的属性,而无法变为nil,释放记忆体。

tags: 铁人赛

<<:  Day 16. slate × Interfaces × CustomType

>>:  冒险村16 - customize breadcurmb

Vue.js 从零开始:props 元件的沟通

上篇component元件有说到每个元件范围都应该是独立的,更不应该发生子元件直接改变根元件的情况,...

Day60 (React)

1.跟资料库连线(目前抓data.json) 影片react06.mp4 (1)Lab_WebAPI...

[Report] 怎麽让筛选条件可以复选

1.add report 2.add dataset 3.edit param be mulit 2...

【Day 19】使用 Terraform 部署 AWS Outposts 资源

tags: 铁人赛 AWS Outposts EC2 Terraform 前情提要 昨天已经完成 E...

成为工具人应有的工具包-06 WirelessKeyView

WirelessKeyView 今天来认识 WirelessKeyView这个酷东西! (还有其他密...