【iOS】引用计数与autorelease

news2024/11/20 6:17:08

文章目录

  • 前言
  • 一、什么是自动引用计数
  • 二、内存管理/引用计数
  • 三、内存管理的思考方式
  • 四、release与autorelease
  • 五、赋值的引用计数


前言

最近在学习iOS内存管理之引用计数,特此撰写博客记录学习过程


一、什么是自动引用计数

自动引用计数(ARC)是指内存管理中对引用计数采取自动计数的方式

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

这些优点无疑极具吸引力,但关于ARC技术,最重要的还是下面这一点:

“在LLVM编译器中设置ARC为有效状态,就无需再次键入retain或者是release代码。”

二、内存管理/引用计数

iOS中的引用计数是一种内存管理机制,用于追踪和管理内存的使用情况。每个对象都有一个引用计数器,用于记录有多少个指针指向该对象。

当对象被创建时,其引用计数器会被设置为1。当一个指针指向该对象时,引用计数器会增加1。如果有一个指针不再指向该对象,那么引用计数器会减少1。当引用计数器为0时,系统会自动释放对象的内存空间。

我们以办公室开灯关灯为例距离说明我们OC的引用计数:
此时的对象相当于我们办公室的照明设备
在这里插入图片描述
我们以一张图来理解我们引用计数的内存管理:
在这里插入图片描述

三、内存管理的思考方式

我们以开灯关灯为例子简单地了解了我们内存管理的机制,那么在OC中我们该如何进行我们的内存管理呢?

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

对象操作与OC方法的对应

对象操作Objective-C方法
生成并持有对象alloc/new/copy/mutableCopy等
持有对象retain
释放对象release
废弃对象dealloc

接下来我们详细了解一下各个思考方式:

  1. 自己生成的对象,自己持有

使用alloc,new,copy,mutablecopy名称开头的方法意味着自己生成的对象只能自己持有
我们这里的自己对应着对象的使用环境,也可以说是编程人员自身

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

例如上述两种方法是完全一致的,我们使用alloc方法创建对象意味着自己生成的对象自己能够持有。

另外使用对这些名称使用驼峰命名法我们也可以自己生成并持有对象,例如:

  • allocMyObject
  • newThatObject
  • copyThis
  • mutableCopyYourObject
  1. 非自己生成的对象,自己也能持有

我们通过alloc,new,copy,mutablecopy以外
的方法取得的对象,因为非自己生成并持有,所以自己不是该对象的持有者

但是我们可以通过retain方法成为对象的持有者

//获取非自己生成并持有的对象
id obj = [NSMutableArray array];
//获取到了对象,但是自己并不持有

//自己持有对象
[obj retain];

从上述的举例可以看出,通过retain方法,非自己持有生成的对象跟用alloc/new/copy/mutableCopy方法生成并持有的对象一样,成了自己所持有的。

我们在上文说到我们通过alloc/new/copy/mutableCopy以外方法取得的对象存在,但自己不持有对象,是如何实现的呢?

解释:
这是因为它们在被创建时并没有任何对象对它们进行retain同时在对象被创建之后对对象使用了autorelease方法
我们以以下代码为例阐述我们非自己生成并持有的对象生成的过程

- (id)object {
    id obj = [[NSObject alloc] init];
    [obj autorelease];
    return obj;
}

通过查看NSMutableArray的这些类方法的实现,你会发现它们内部都调用了 autorelease 方法。

通过alloc等之外方法创建的对象在创建时会被自动加入到当前的autorelease pool中。Autorelease pool是一个特殊的对象,它持有一组对象,并会在合适的时候释放这些对象。这就是为什么我们通过alloc,new,copy,mutablecopy以外
的方法取得的对象非自己生成并持有。

  1. 不再需要自己持有的对象时释放

自己持有的对象,一旦不再需要,持有者有义务释放该对象,释放使用release方法。
例如:

//自己生成并持有对象
id obj = [[NSObject alloc] init];

//释放对象
[obj release];

这样一来我们的对象的引用计数为0,对象已经被释放,我们的obj无法再次访问我们的对象,如果访问会导致程序崩溃

同样,自己生成而非自己所持有的对象,若使用retain方法持有,同样也可以使用release释放。

  1. 无法释放非自己持有的对象
//自己生成并持有对象
id obj = [[NSObject alloc] init];

//自己持有对象

[obj release];

//对象已释放 

[obj release];
/*
释放之后再次释放已非自己持有的对象!
应用程序崩溃!

崩溃情况:
再度废弃已经废弃了的对象时崩溃
访问已经废弃的对象时崩溃
*/

在第一次release之后我们的对象已经被释放,如果再次释放会导致程序崩溃

四、release与autorelease

release是一个立即释放对象的方法。当你调用release时,对象的引用计数会立即减少,如果引用计数达到0,对象会被立即释放。因此,release需要在不再需要对象时手动调用,以避免内存泄漏。

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

这里需要注意的是我们只有在MRC中才可以使用releaseautorelease对我们的对象进行内存管理。
ARC环境中我们使用release方法会报错,因为我们的编译器自动帮我们进行了内存管理

同时在《Objective-C高级编程-iOS与OS+X多线程和内存管理》中说道:我们使用autorelease方法时,可以使取得的对象存在,但自己不持有对象。这样的功能可以使对象超出指定生存范围时能够自动并正确地释放,如下图所示:
在这里插入图片描述

对于release方法我们这里不再讲述,我们主要讲一下autorelease方法

autorelease方法听起来很像ARC,但其实它更像c语言中的局部变量,当我们的局部变量超出其作用域时,我们的局部变量会被自动废弃
在这里插入图片描述

autorelease像c语言中对待局部变量一样来对待对象,当对象超出作用域,对象实例的release方法会被自动调用

与C语言中的局部变量不同的是,我们可以设定我们变量的作用域

在这里插入图片描述
在这里插入图片描述
调用autorelease的对象,在废弃NSAutoreleasePool对象时,都将会调用release方法,用源码表示如下:

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    id obj = [[NSObject alloc] init];
    [obj autorelease];
    [pool drain];
     NSLog(@"%lu", [obj retainCount]);

这段代码执行下来,我们的obj会在pool drain之后自动销毁,之后我们就无法再次访问obj对象

当然在使用autorelease方法时还会有另外一种情况:

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    id obj = [NSMutableArray array];
    [obj autorelease];
    [pool drain];
     NSLog(@"%lu", [obj retainCount]);

如果我们将alloc方法替换为array方法时,我们的这段程序会报错,这是因为我们的array方法内部已经自动帮我们生成了一个NSAutoreleasePool对象,当我们再次手动创建一个NSAutoreleasePool对象时并进行[pool drain];操作时,手动创建的NSAutoreleasePool对象与自动创建NSAutoreleasePool的对象都会将obj加入释放池的数组中,因此对我们手动创建的pool对象进行销毁操作时也意味着我们array方法内部的自动释放池被销毁,obj的引用计数为0,被自动销毁

五、赋值的引用计数

我们代码中常用的赋值方式有两种,一种是直接赋值,一直是通过setter方法进行赋值

我们给出代码例子:

a.room = r;//setter
id obj1 = obj;//直接

a是一个对象,并且r是对另一个对象的引用,那么这段代码实际上是在将a对象的room属性设置为r引用的对象。

在这种情况下,如果a对象的r属性原来持有一个不同的对象,那么那个对象的引用计数会减1,而新的对象的引用计数会加1。这是因为当你将一个对象的属性设置为另一个对象时,你实际上是在增加对新对象的引用,同时减少对原对象的引用。

如果room属性原来没有持有对象,那么仅仅会对新的对象的引用计数加1。

    preson *a = [[preson alloc] init];
    preson *b = [[preson alloc] init];
    room *r = [[room alloc] init];
    r.no = 888;
    a.room = r;//是新对象引用计数加1
    b.room= r;
    NSLog(@"%lu", [r retainCount]);

在这里插入图片描述

对于id obj1 = obj;,这段代码只是创建了一个新的引用obj1,它引用的是obj对象。这个操作并没有改变obj的引用计数,因为obj1只是对obj的一个新引用,并没有增加或减少obj的引用计数。

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

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

相关文章

在支付宝小程序上websocket实现mqtt协议连接服务器控制硬件

概述 支付宝小程序作对外开放,有许许多多的好玩的地方,那么本文就在支付宝小程序上websocket实现mqtt协议连接服务器控制智能硬件!! 详细 一、前言; 那么本系列连载的博文,都是围绕着 支付宝小程序如何实…

9月25日星期一,早安心语早安问候语早读

1、 人生的幸福,一半要争,一半要随,争,不是与他人,而是与困苦,随,不是随波逐流,而是知止而后安,争,人生少遗憾;随,知足者常乐&…

Oracle 创建用户及模式

目录 1. 简言 2. 创建表空间 3. 创建用户与上面创建的文件形成映射关系 4. 添加权限 5. 登录 1. 简言 Oracle 创建数据库与用户一般一一对应, 准确的说可以 Oracle 中的 Schema 相当于 MySQL 中的数据库. Oracle 不支持创建自定义模式的, 想要创建模式的话只能新建一个用户…

Linux基础指令(五)

目录 前言1. 打包和压缩1.1 是什么1.2 为什么1.3 怎么办? 2. zip & unzip3. tar 指令结语: 前言 欢迎各位伙伴来到学习 Linux 指令的 第五天!!! 在上一篇文章 Linux基本指令(四) 当中,我们学习了 fin…

C++标准模板(STL)- 输入/输出操纵符-(std::endl)

操纵符是令代码能以 operator<< 或 operator>> 控制输入/输出流的帮助函数。 不以参数调用的操纵符&#xff08;例如 std::cout << std::boolalpha; 或 std::cin >> std::hex; &#xff09;实现为接受到流的引用为其唯一参数的函数。 basic_ostream::…

计算机毕设 基于大数据的抖音短视频数据分析与可视化 - python 大数据 可视化

文章目录 0 前言1 课题背景2 数据清洗3 数据可视化地区-用户观看时间分界线每周观看观看路径发布地点视频时长整体点赞、完播 4 进阶分析相关性分析留存率 5 深度分析客户价值判断 5 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;…

微信小程序的无限瀑布流写法

微信小程序的无限瀑布流实现总算做完了&#xff0c;换了好几种方法&#xff0c;过程中出现了各种BUG。 首先官方有瀑布流的插件&#xff08;Skyline /grid-view&#xff09;&#xff0c;不是原生的我就不想引入&#xff0c;因为我的方块流页面已经搭好了&#xff0c;引入说不定…

时空智友企业流程化管控系统任意文件上传漏洞复现【附POC】

文章目录 时空智友企业流程化管控系统任意文件上传漏洞复现0x01 前言0x02 漏洞描述0x03 影响平台0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现4.访问shell地址 0x06 修复建议 时空智友企业流程化管控系统任意文件上传漏洞复现 0x01 前言 免责声明&#xff1a;请…

股票难还是期货难?国内玩期货的人多吗?

股票和期货都是相对较难的金融投资工具。它们都有各自的优点和挑战&#xff0c;而且都需要深入了解市场、制定策略和进行风险管理。 就难度而言&#xff0c;期货和股票的难度主要在于以下方面&#xff1a; 1. 市场风险&#xff1a;股票和期货市场都存在风险&#xff0c;包括价格…

【沐风老师】3DMAX翻转折叠动画插件FoldFx使用方法详解

3DMAX翻转折叠动画插件FoldFx使用方法详解 3DMAX翻转折叠动画插件FoldFx&#xff0c;是3dMax运动图形工具&#xff0c;用于创建多边形折叠动画。用户几乎有无限的可能性&#xff0c;因为动画的每个方面都是可控的。 【适用版本】 适用于3dMax版本&#xff1a;2010及更新版本&a…

QT6.5.2编译PostgreSql驱动

一、环境 1、操作系统&#xff1a;win11 2、qt版本&#xff1a;6.5.2 3、PostgreSql版本:14.9 二、下载qbase源码 1、下载地址&#xff1a;https://github.com/qt/qtbase/tree/6.5.2 将下载的源码文件解压指定的的目录&#xff0c;找到src/plugins/sqldrivers根据自己的实…

基于springboot+vue的校园资产管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

小皮面板配置Xdebug,调试单个php文件

小皮面板配置Xdebug 首先下载phpstrom&#xff0c;和小皮面板 打开小皮面板&#xff0c;选中好要使用的php版本 然后点击【管理】> 【php扩展】> 【xdebug】 然后打开选中好版本的php位置 D:\Program_Files\phpstudy_pro\Extensions\php\php7.4.3nts打开php.ini文件…

[0CTF 2016]piapiapia 代码审计 字符串逃逸 绕过长度限制

第一次直接打包代码 然后查看有没有洞 学习一下 降低速度扫描dirsearch -t 2 超低速 扫描扫到了 /www.zip /profile.php /register.php /upload/ 未加参数 我们直接去看看 我们直接下载备份文件即可 config.php 存在flag变量 class.php 然后我们分析一下class.php &…

Visual Studio 2019 C# winform CefSharp 中播放视频及全屏播放

VS C# winform CefSharp 浏览器控件&#xff0c;默认不支持视频播放&#xff0c;好在有大佬魔改了dll&#xff0c;支持流媒体视频播放。虽然找了很久&#xff0c;好歹还是找到了一个版本100.0.230的dll&#xff08;资源放在文末&#xff09; 首先创建一个项目 第二、引入CefSha…

VMware安装debian11虚拟机详细步骤

VMware安装debian11虚拟机详细步骤&#xff0c;超详细&#xff0c;一次搞定。 目录 1&#xff0c;新建虚拟机 2&#xff0c;开始安装 3&#xff0c;磁盘分区&#xff08;手动&#xff09; 分区设置 配置LVM卷 4&#xff0c;软件包管理器、网络镜像等 5&#xff0c;完成安…

UOS 序列号激活指令及方法

前言&#xff1a;本方案主要介绍了6种不同的激活方式&#xff0c;包括 1、在线激活&#xff1b; 2、离线激活&#xff1b; 3、激活文件激活&#xff1b; 4、终端命令激活&#xff1b; 5、试用期激活&#xff1b; 6、测试激活码激活。 附&#xff1a;激活码正版验证网页&#xf…

Fedora Linux 39 Beta 预估 10 月底发布正式版

Fedora 39 Beta 镜像于今天发布&#xff0c;用户可以根据自己的使用偏好&#xff0c;下载 KDE Plasma&#xff0c;Xfce 和 Cinnamon 等不同桌面环境版本&#xff0c;正式版预估将于 10 月底发布 Fedora 39 Beta 版本主要更新了 DNF 软件包管理器&#xff0c;并优化了 Anaconda …

kotlin的集合使用maxBy函数报NoSuchElementException

kotlin设定函数 fun test() {listOf<Int>().maxBy { it } } 查看java实现

Vue+iview 组件中通过v-for循环动态生成form表单进行表单校验

在做项目时&#xff0c;需要根据需要动态添加或新增表单&#xff0c;同时还需要对表单做校验。详情如下图&#xff1a; 刚开始做表单验证的时候&#xff0c;对于这个动态的表单验证有点难搞&#xff0c;试了好几种方法都没有搞定。最后按照下面这种方法实现了&#xff0c;以此…