| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Swift基础入门知识学习(19)-自动引用计数(自动参考计数ARC)-讲给你懂 -> 正文阅读 |
|
[移动开发]Swift基础入门知识学习(19)-自动引用计数(自动参考计数ARC)-讲给你懂 |
Swift基础入门知识学习(18)-构造过程(建构过程及解构过程)-讲给你懂 理解难度 Swift 使用自动引用计数(ARC, Automatic Reference Counting)机制来追踪与管理记忆体使用状况,所以大部分情况下,你不需要自己管理,Swift 会自动释放掉不需要的记忆体。 引用计数只应用在类(也就是参考类型)的实例。结构体与枚举为值类型,也不是通过引用的方式储存与传递。 自动引用计数的运作方式当一个类实例被指派值(给一个属性、常量或变量)的时候,会建立一个该实例的强引用(strong reference),同时会将引用计数(reference counting)加 1 ,强引用表示会将这个实例保留住,只要强引用还在(也就是引用计数不为 0 ),储存这个实例的记忆体就不会被释放掉。 下面介绍一下 ARC 运作的方式:
类实例间的强引用循环ARC 在大部分时间都可以运作顺利,但在有些情况下会造成强引用永远不会归零,进而发生记忆体泄漏(memory leak)的问题。 下面是一个例子,两个类彼此都拥有对方强引用的属性,一个实例要释放记忆体前,必须先释放对方强引用,而对方要释放前也是要原本实例先释放,进而产生强引用循环:
接着把这两个不同的实例联系起来,如下:
前面提过,上面的代码中,在实例后的惊叹号(!)指的是将一个可选类型强制解析,也就是隐式解析可选类型。 解决实例间的强引用循环Swift 提供了两种办法来解决强引用循环,分别是弱引用(weak reference)及无主引用(unowned reference)。 这两种引用也能引用实例,但因为不是强引用,所以不会保留住实例的引用(也就是这个实例的引用计数不会增加)。 而两者的差别在于,如果一个引用这个实例的变数在生命周期中,可能会为nil时,就使用弱引用,而在初始化之后不会再变为nil的则是使用无主引用。 弱引用弱引用(weak reference)也能引用实例,但不会保留住引用的实例(所以这个实例的引用计数不会增加)。而一个引用这个实例的变数在生命周期中可能没有值(为nil)时,就使用弱引用。 弱引用必须宣告为变数,表示可以被修改,同时也必须是可选类型(optional),因为可能没有值(为nil)。 弱引用使用weak关键字来定义,下面将前面强引用循环的例子改写,将类Apartment内的属性tenant改为弱引用(因为公寓可能有时没有住户,即有时会没有值,适合使用弱引用):
无主引用与弱引用一样,无主引用(unowned reference)不会保留住引用的实例(所以这个实例的引用计数不会增加),但不同的是,无主引用会被视为永远有值,所以需要被定义为非可选类型,而因此可以直接存取,不需要强制解析(即加上惊叹号!)。 无主引用使用unowned关键字来定义,下面例子将介绍一个使用者类Customer与信用卡类CreditCard之间的关系,使用者不一定有信用卡,但当产生出信用卡时,这信用卡一定属于某个使用者:
无主引用和隐式解析可选类型除了上面的两种情况,还有一种情况为,两个互相引用实例的属性都必须有值,且初始化后永远不为nil,这时要在其中一个类使用无主引用,另一个类使用隐式解析可选类型。 当初始化完成后,这两个属性都能被直接存取(不需要强制解析,即不用加上惊叹号 !),且也避免了强引用循环。 下面的例子分别定义了类Country及类City,每个类都有一个储存对方类实例的属性,也就是每个国家(Country)都有一个首都(capitalCity),而一个城市(City)必须属于一个国家(country):
上面的代码中,为了建立两个类的依赖关系,City的建构函数有一个Country实例的参数,并储存为country属性。Country的建构函数则呼叫了City的建构函数。 以Country来说: 在构造器中要使用self代表自己本身,必须要在自己初始化完成后才行。而Country的建构函数中,在name设置完值后就完成了初始化,所以可以将self(即本身)当做参数传给City的建构函数。 以City来说: City在country属性使用了无主引用,因为一个城市一定属于一个国家,所以一定有值,且不会增加Country实例的引用计数。(其实就如同前面例子Customer之于CreditCard的关系) 以上的意义在于可以通过一条语句同时生成Country跟City的实例,而不会产生强引用循环,并且capitalCity属性可以被直接存取,不需要被强制解析(即加上惊叹号!)。 闭包的强引用循环除了前面提到的类实例之间可能产生强引用循环,当将一个闭包(closure,也就是匿名函数)设置给一个类实例的属性时,这个闭包函数内存取了这个实例的某个属性,或是呼叫了实例的一个方法,都会导致闭包捕获(capture)了self,进而产生了强引用循环。 闭包所捕获的引用会被自动视为强引用。这个强引用循环的产生,是因为闭包也是引用类型,当把闭包设置给一个属性时,实际上是设置了闭包的引用。 下面是一个闭包与类实例的强引用循环的例子:
闭包中虽然多次使用了self,但只捕获了 1 个强引用(也就是引用计数只算 1 次) 解决闭包的强引用循环在定义闭包时,同时定义捕获列表(capture list)作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的强引用循环。捕获列表中必须定义每个闭包中捕获的引用为弱引用或无主引用(依其相互关系来决定)。 定义捕获列表捕获列表(capture list)中每一项都以weak或unowned关键字与类实例的引用(如self)或初始化过的变数(如delegate = self.delegate!)成对组成,每一项以逗号 , 隔开,并写在中括号[ ]内。 下面为捕获列表的格式:
下面则是将前面的例子HTMLElement中的闭包加上捕获列表,便可以避免强引用循环:
这个部分能看懂就看,觉得不容易理解,就先浏览过有个概念也就够了。 |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 9:02:59- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |