当前位置: 首页 > news >正文

【iOS】引用计数(一)

【iOS】引用计数

文章目录

  • 【iOS】引用计数
    • 前言
    • ARC与MRC
    • 什么是引用计数的机制
    • 内存管理的思考方式
      • 自己生成的对象
      • 非自己生成的对象
      • 不再需要自己持有就释放
      • 无法释放非自己持有的对象
    • autorelease
    • 小结

前言

笔者最近开始学习了一下有关于引用计数的内容,写这篇博客来简单认识一下引用计数部分的内容。

ARC与MRC

ARC就是自动引用计数,指的是OC中对于引用计数采取一个自动计数的方式。

在Objective-C中采用Automatic Reference Counting
(ARC)机制,让编译器来进行内存管理。在新一代Apple
LLVM编译器中设置ARC为有效状态,就无需再次键入retain或者release代码,这在降低程序崩溃、内存泄漏等风险的同时,很大程度上减少了开发程序的工作量。编译器完全清楚目标对象,并能立刻释放那些不再被使用的对象。如此来,应用程序将具有可预测性,且能流畅运行,速度也将大幅提升。

MRC则是由程序员手动进行内存管理,很显然ARC极大的提高了开发效率,也可以让程序更加流畅的运行。

什么是引用计数的机制

我们可以通过一个开关灯的思路去理解这部分内容,

在这里插入图片描述

正如上图所展示的,我们办公室在第一个人来的时候就要开灯,在最后一个人走后就要关灯,不能在当一个人走后就进行一个关灯操作,这样会影响其他人工作,所以只有当最后一个人离开办公室的时候再关灯就好了,这样才可以让其他人正常工作,而我们创建的对象可以理解为办公室里的照明设备,只要有一个人工作,照明设备就不可以被关闭。

OC中对应的一个状态对照明设备的操作
生成对象开灯
持有对象办公室还有人需要照明
释放对象不需要照明
废弃对象关灯

可以看到这里对象是否要被释放和我们这里办公室里面是否还有人关系非常密切,所以OC就采用了一种引用计数的方式来记录该对象是否要被释放,我们分析一下灯的开关被打开的几个过程,首先开始是没有人的状态这时候引用计数为0,后面有第一个人之后,引用计数为1,然后又来一个人引用计数为2,然后有人离去的时候引用计数减一,最后一个人离开的时候引用计数再减一,这时候我们就可以把这个灯关掉,这里我们把上述的灯改成对象,所以这里就简单介绍了我们对象的概念。

在这里插入图片描述

下面这张图就展示了我们的引用计数这个机制的几个步骤。

内存管理的思考方式

我们思考内存管理的时候,往往会过于关注计数这个问题,但是实际上计数反而不是重点,我们真正的应该思考的应该是如下四个方式来分引用计数。

  • 自己生成的对象,自己持有;
  • 非自己生成的对象,自己也能持有;
  • 不再需要自己持有的对象时释放;
  • 非自己持有的对象无法释放。

在这里插入图片描述
这个表格给出了OC中对应的操作。

自己生成的对象

id obj = [[NSObject alloc] init];id obj = [NSObject new];这两个都是自己生成对象自己持有。

我们按着驼峰命名法也可以来自己生成并且持有对象。

非自己生成的对象

我们使用出来非上述的方式也可以取得一个对象,但是因为不是通过自己生成并且持有的方式创建的,所以我们通过类似[NSMutableArray array]的方式创建的,我们还没有实现持有这个步骤,所以我们需要进行一个持有的过程.

id obj = [NSMutableArray array];
[obj retain];

这个方法的底层实现原理其实是通过一个autorealse这个方式来实现的,至于这个方法是如何实现的我们后面简单介绍一下。

id obj = [[NSObject alloc] init];
[obj autorelease];

这里就实现一个持有的操作,这里的对象并非自己创建但是仍然可以持有该对象。

不再需要自己持有就释放

简单来说就是我们不需要持有这个对象的时候,我们就需要调用release这个代码来实现一个释放的效果,比方说:

id obj = [NSMutableArray array];
[obj retain];
[obj release];

这里注意一下,如果一个对象一经释放就不可以再访问了。

无法释放非自己持有的对象

在OC中我们也无法释放非自己持有的对象,举个例子:

id obj = [[NSObject alloc] init];[obj release];[obj release];

根据前面我们说的内容,这里我们如果已经release过一次,obj所持有的对象已经被废弃了,所以我们在释放一次的话就会出现一个程序崩溃的问题。

其实我们可以总结为以下四个方面:

在这里插入图片描述

autorelease

我们上面提到了autorelease,这里我们就来简单介绍一下有关autorelease的内容。

而autorelease是一种延迟释放对象的机制。当一个对象被autorelease时,它的引用计数不会立即减少,而是在当前autorelease pool被销毁时才会减少。
这意味着,即使你不再使用一个对象,它也不会立即被释放,而是等待当前Runloop结束时才会被释放。因此,autorelease可以在需要延迟释放对象时使用,以避免频繁释放和创建对象带来的性能开销。

在这里插入图片描述

他最大好处在于可以使取得的对象存在但是自己并不持有对象。

我们可以把它理解成一个C语言中的局部变量,C语言中的局部变量是在我们的变量超出自己的作用域的时候会被自动废弃,那么这里则是一个对象如果离开了autorelease的池中他会自己调用release这个方法。下面给出如何使用autorelsease,他有一优势就是我们可以定义变量的作用域。

在这里插入图片描述

这里我们按照上图的要求编写下面这段代码:

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];id obj = [[NSObject alloc] init];[obj autorelease];[pool drain];NSLog(@"%lu", [obj retainCount]);//这里会报错,因为我们无法访问到这个对象

上面这段代码展示了我们如何使用autorelease这个方法,这里的[pool drain];相当于[obj release]

但是实际上我们的编译器会自己创建NSAutoreleasePool这个类的对象,就好比我们的NSMutableArray这个类

 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];id obj = [NSMutableArray array];[obj autorelease];[pool drain];

这段代码会报错,主要原因是我们在创建NSMutableArray这个类的对象的时候,编译器会自动创建一个NSAutoreleasePool然后这个池子被放进了我们之前手动创建的NSAutoreleasePool这个池子中,所以他会把池子给释放,然后就会释放我们的数组,从而导致了我们的数组引用计数已经为0,导致代码报错。

小结

这里笔者对于引用计数进行了一个简单的学习,简单了解了他的一个相关实现,后面还会继续进行补充学习。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 0基础学习HTML(十一)列表
  • xilinx hbm ip运用
  • 什么是堡垒机?运维为什么需要堡垒机?
  • Apache James配置连接达梦数据库
  • ldd可以显示出程序启动时需要静态加载的动态库的完整列表
  • CMake中如何使用全局配置文件来配置项目
  • 828华为云征文 | 云服务器Flexus X实例:one-api 部署,支持众多大模型
  • 【数据结构-二维差分】力扣2536. 子矩阵元素加 1
  • Kafka-Go学习
  • 5.内容创作的未来:ChatGPT如何辅助写作(5/10)
  • 算法题之每日温度
  • Vue学习记录之三(ref全家桶)
  • 山东潍坊戴尔存储服务器维修 md3800f raid恢复
  • Spring:项目中的统一异常处理和自定义异常
  • MATLAB入门基础篇
  • [Vue CLI 3] 配置解析之 css.extract
  • es6要点
  • JavaScript中的对象个人分享
  • Java基本数据类型之Number
  • Redash本地开发环境搭建
  • SpingCloudBus整合RabbitMQ
  • Wamp集成环境 添加PHP的新版本
  • webpack入门学习手记(二)
  • 初识MongoDB分片
  • 从零开始在ubuntu上搭建node开发环境
  • 大快搜索数据爬虫技术实例安装教学篇
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 规范化安全开发 KOA 手脚架
  • 扑朔迷离的属性和特性【彻底弄清】
  • 前端面试题总结
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 使用docker-compose进行多节点部署
  • 使用SAX解析XML
  • 探索 JS 中的模块化
  • 一道面试题引发的“血案”
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​插件化DPI在商用WIFI中的价值
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (zt)最盛行的警世狂言(爆笑)
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (附源码)ssm高校志愿者服务系统 毕业设计 011648
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (算法)Travel Information Center
  • (转)winform之ListView
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • ../depcomp: line 571: exec: g++: not found
  • ./configure,make,make install的作用(转)
  • .describe() python_Python-Win32com-Excel
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .NET Core 和 .NET Framework 中的 MEF2