引用计数

《iOS开发进阶》读书笔记


 

引用计数

引用计数可以有效地管理对象的生命周期。当我们创建新对象的时候,他的引用计数为1,当有一个指针指向这个对象时,我们将其引用计数加1,当某个指针不再指向这个对象时,我们将其引用计数减1.当对象的引用计数变为0时,说明这个对象不再被任何指针指向了,这个时候我们就可以将对象销毁,回收内存。

我们为什么需要引用计数?

假如对象A生成一个对象M,需要调用对象B的某一个方法,把对象M作为参数传递过去。在没有引用技术的情况下,一般内存管理的原则是“谁申请,谁释放”,那么对象A就需要在对象B不再需要M的时候将对象M销毁。但对象B可能致死临时用一下对象M,也可能觉得M很重要将他设置为一个成员变量,在这种情况下,什么时候释放对象M成了一个难题。

有一个暴力的方法就是对象A调用完对象B之后立马销毁参数对象M,然后对象B需要另外将参数复制一份,生成另一个对象M2,然后自己管理对象M2的生命周期。但是这种做法有一个很大的问题就是他带来更多的内存申请、复制、释放的工作。本来一个可以服用的对象,因为不方便管理他的生命期就简单的把他销毁然后又重新构造一份,实在是太影响性能。

我们还有一个方法,就是对象A构造完对象M之后,始终不销毁对象M,由对象B来完成对象M的销毁工作。如果对象B需要长时间使用对象M,就不销毁他,如果只是临时用一下就可以用完后马上销毁。这种做法看似很好的解决了对象复制的问题,但是他强烈依赖于A、B两个对象的配合,代码维护者需要明确记住这种编程约定。而且,由于对象M申请在A中,释放在对象B中,使得它的内存管理代码分散在不同对象中,管理起来也非常费劲。如果这个时候情况再复杂一点,例如,对象B需要再向对象C传递对象M,那么这个对象在对象C中又不能让对象C管理。所以这种方式带来的复杂性更大,更不可取。

 

 

所以引用计数解决了这个问题,在传递参数M的过程中,哪些对象需要长时间使用这个对象,就把他的引用计数加1,使用完了之后再把引用计数减1.所有对象都遵守这个规则的话,对象的生命期管理就可以完全交给引用计数了。

 

不要向已经释放的对象发送消息

当我们想去打印查看引用计数时,我们会尝试使用如下代码(非ARC环境下):

但是我们得到的结果却是这样的:

我们注意到最后一次输出引用计数并没有变成0.这是为什么?因为该对象的内存已经被回收,而我们向一个已经被回收的对象发了一个retainCount消息,所以他的输出结果应该是不确定的,如果该对象占用的内存被复用,那么就有可能造成程序异常崩溃。

那么为什么在这个对象被回收之后,这个不确定的值是1而不是0呢?这是因为当最后一次执行release时,系统知道马上就要回收内存了,就没有必要再将retainCount减1了,因为不管减不减1,该对象都肯定会被回收,而对象呗回收后,他的所有内存区域,包括retainCount值也变得没有意义。不将这个值从1变成0,可以减少一次内存的操作,加速对象的回收。

 

循环引用的问题

引用计数这种管理内存的方式虽然很简单,但是有一个比较大的瑕疵,即它不能很好地解决循环引用的问题。对象A和对象B,相互引用对方作为自己的成员变量,只有自己销毁时才会将成员变量引用计数减1.因为对象A的销毁依赖于对象B的销毁,对象B的销毁又依赖于对象A的销毁,这样就造成了循环引用的问题。

解决循环引用的问题主要有两个办法。

第一个办法就是明确知道这里会有循环引用,在合理的位置断开环中的一个引用,使得对象得以回收。

第二个方法是弱引用的方法。这个方法更为常用。弱引用虽然持有对象但是并不增加引用计数,这样就避免了循环引用的产生。iOS开发中的delegate常用弱引用方式。

 

不知道引用计数原理过度依赖ARC

过度依赖ARC的iOS新人们,由于不知道引用计数,他们的问题主要体现在两个方面:

1.过度使用block之后无法解决循环引用的问题。

2.遇到底层Core Foundation对象,需要手工管理他们的引用计数时,显得一筹莫展。Core Foundation对象的内存管理:

 
对于CFRetain和CFRelease两种方法,可以理解为和Objective-C对象的retain和release方法等价。
在ARC下,还有一个问题需要解决。我们有时需要将一个Core Foundation对象转换成一个Objective-C对象,这时候我们需要告诉编译器,转换过程中的引用计数如何调整。这就引入了与bridge相关的关键字,以下是这些关键字的说明:
1.__bridge:只做类型转换,不修改相关对象的引用计数,原来的Core Foundation对象在不用时,需要调用CFRelease方法。
2.__bridge_retained:类型转换后,将相关对象的引用计数加1,原来的Core Foundation对象在不用时,需要调用CFRelease方法。
3.__bridge_transfer:类型转换后,将该对象的引用计数交给ARC管理,Core Foundation对象在不用时,不需要调用CFRelease方法。

转载于:https://www.cnblogs.com/sunjianfei/p/7061099.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/416525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

10kv开关柜价格_一进三出10KV负荷开关环网柜乌兰察布

一进三出10KV负荷开关环网柜乌兰察布阻碍了开关柜的运行。开关柜发生拒动或误动时,严重影响了周围的电网系统,促使电网系统潜在很大的安全风险。开断、关合故障,是由断路器引起的,干预了高压开关柜的安全状态。例如:高…

git前端工程实现ci_大前端项目代码重用,也许lerna是最好的选择

我前段时间参与了一个react为主的大前端项目,覆盖Web、Android、Ios三个平台。由于整个业务逻辑侧重在手机端,且Web端也是到了项目中期才开始启动,我在搭底层框架时就没有考虑用类似react-native-web这样的框架把三端统一,而是分别…

在保护继承中基类的共有成员_C#初学者教程系列11:继承

本文是C#初学者简单教程,这是第11篇。感谢观看,记得关注我,后续还有更多教程文章,谢谢。本文环境为Visual Studio 2019。一、什么是继承继承是面向对象编程的一种基本特性。 借助继承,能够定义可重用(继承)、扩展或修改…

怎么使用java官方demo?

//官方的例子在质量上是有保证的,而各种教程和文档又局限于个人阅读和理解力。 进入jdk官网---找download,,,下滑鼠标----找到如: JDK 8 Demos and Samples 点击下载,,解压进入,比如…

分布式锁防止订单重复提交_防止表单重复提交看这里!!!

要解决重复提交这事,先要知道什么是重复提交假如用户的网速慢,用户点击提交按钮,却因为网速慢,而没有跳转到新的页面,这时的用户会再次点击提交按钮,举个例子:用户点击订单页面,当点…

python实战之编码问题:中文!永远的痛

python实战之编码问题:中文!永远的痛 编码的思维图谱: 也就是说文件没有编码之说,事实上都是按二进制格式保存在硬盘中的。不过在写入读取时须使用相应的编码进行处理,以便操作系统配合相关软件/字体,绘制到…

自动打包_全自动打包机行业发展如何?全自动打包机行业发展现状分析

全自动打包机行业发展如何?全自动打包机行业发展现状分析随着经济的快速发展,现在很多产品的生产过程都变得简单起来,更新换代也非常快,这不仅促进了企业的发展,也提高了人们生活质量。全自动打包机作为企业生产中常见…

小可爱

转载于:https://www.cnblogs.com/lrf9606/p/7077434.html

13新功能_再聊聊灵感盒 -Marginnote 3.6.12/13新功能

我是夜雨,水群最多的一类人本文主要BB了我对灵感盒的理解Marginnote 3.6.12/13个人之前对灵感盒的理解在此强调开发者的一句话不要对灵感盒做太多高大上的引申灵感盒只不过是新的脑图结构关于灵感盒的延伸Zattelkasten/slip box/卡片盒笔记法该内容很早之前就在Marg…

局域网抢答器_基于童芯派的抢答器V1.0

[童心制物Makeblock]的新产品"童芯派"发布已两月有余,刚一发布就第一时间入手三个含扩展板的套装,Makeblock的产品我还是很认可的,从mbot,ranger到程小奔,从神经元,光环版到童芯派,东…

下拉框_教你封装 Element Tree 树状下拉框

在日常项目开发中,树状下拉框的需求还是比较常见的,但是element并没有这种组件以供使用。在这里,小编就基于element如何封装一个树状下拉框做个详细的介绍。通过这篇文章,你可以了解学习到一个树状下拉框组件是如何一步一步封装成…