【iOS】ARC学习

文章目录

  • 前言
  • 一、autorelease实现
  • 二、苹果的实现
  • 三、内存管理的思考方式
    • __strong修饰符
      • 取得非自己生成并持有的对象
      • __strong 修饰符的变量之间可以相互赋值
      • 类的成员变量也可以使用strong修饰
    • __weak修饰符
      • 循环引用
    • __unsafe_unretained修饰符
      • 什么时候使用__unsafe_unretained
    • __autoreleasing修饰符
      • 访问附有__weak 修饰符的变量时,实际上必定要访问注册到autoreleasepool的对象
  • 四、ARC规则
    • 不要显式调用dealloc
  • 五、属性


前言

在学习ARC之前,先来复习一下内存管理以及autorelease的实现

一、autorelease实现

先来看一下GNUstep源代码:
在这里插入图片描述
autorelease其本质就是调用NSAutoreleasePool 对象的addObject 类方法,就是将对象加到自动释放池中
在这里插入图片描述
接下来再看一下废弃自动释放池的一些功能函数
在这里插入图片描述

二、苹果的实现

可使用showPools输出现在的NSAutoreleasePool的状况输出到控制台

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];id obj = [[NSObject alloc] init];id obj2 = [[NSObject alloc] init];id obj3 = [[NSObject alloc] init];[obj autorelease];[obj2 autorelease];[obj3 autorelease];_objc_autoreleasePoolPrint();[pool drain];

在这里插入图片描述

三、内存管理的思考方式

引用计数式内存管理的思考方式就是思考ARC所引起的变化

ARC有效时,id 类型和对象类型同C语言其他类型不同,其类型上必须附加所有权修饰符。 所有权修饰符一共有4 种

(ARC环境下特有)

  • __strong修饰符
  • __weak修饰符
  • __unsafe_unretained修饰符
  • __autoreleasing修饰符

__strong修饰符

_ strong修饰符是id类型和对象类型默认的所有权修饰符
也就是说id obj = [[NSObject alloc] init]; = id __strong obj = [[NSObject alloc] init];

再来看下面这段代码

//ARC有效
{id __strong obj = [[NSObject alloc] init]
}

此源代码指定了变量的作用域,当obj超出其变量作用域时, obj会被废弃,同时自动释放其被赋予的对象([[NSObject alloc] init])

而在MRC中,等效的代码为

//ARC无效
{id obj = [[NSObject alloc] init][obj release];
}

因为ARC无效的时候,obj超出变量作用域时,变量并不会被自动废弃,对象也会仍然存在,需要我们手动减少对象的引用计数[obj release]去销毁对象

取得非自己生成并持有的对象

具体如下:
在这里插入图片描述
这里需要注意的一点是此处obj确实持有了对象,并且对象的引用计数为1,但是在目前版本的Xcode的MRC环境中,

    {id obj = [NSMutableArray array];NSLog(@"%lu", [obj retainCount]);}

在MRC环境下输出的值应该为0,因为array方法表明取得非自己生成并持有的对象,也就是说obj并不持有对象,但是输出如下:
在这里插入图片描述
我们来解释一下输出为1的原因:

当我们调用 retainCount 方法时,对于从自动释放池获取的对象,它会临时retained一次,以防止对象被过早释放而导致访问过期数据。

1.array方法创建了一个对象,并将其加到自动释放池中,此时retain count为0
2.obj指向自动释放池中的那个对象,并没有对对象进行retain操作,只是持有了一个指向他的指针
3.调用 [obj retainCount] 时 ,a.编译器会临时保留(retain)对象 b.获得并输出其retain count值 c.释放对象

所以尽管对象最初的 retain count 为 0,但由于 retainCount 方法的实现机制,它会临时保留对象来避免崩溃,这导致我们看到的输出 retain count 为 1。

__strong 修饰符的变量之间可以相互赋值

   id __strong obj0 = [[NSObject alloc] init];//对象Aid __strong obj1 = [[NSObject alloc] init];//对象Bid __strong obj2 = nil;obj0 = obj1;//obj0持有有obj1赋值的对象B的强引用,obj0被赋值。所以原先持有的a的强引用失效,此时b的强引用变量为obj1,obj0

由此__strong 修饰符的变量,不仅只在变量作用域中,在赋值上也能够正确地管理其对象的所有者。

类的成员变量也可以使用strong修饰

在这里插入图片描述
在这里插入图片描述
重点是当Test对象释放时,Test对象的obj_成员变量也会随之被释放

__weak修饰符

使用weak可以使我们取得对象但是并不持有对象
下面有一个代码例子进行解释

    id a = [[NSObject alloc] init];id __weak b = a;id c = a;NSLog(@"%lu", CFGetRetainCount((__bridge  CFTypeRef)a));NSLog(@"%lu", CFGetRetainCount((__bridge  CFTypeRef)c));a = nil;NSLog(@"%lu", CFGetRetainCount((__bridge  CFTypeRef)c));NSLog(@"%@", b);NSLog(@"%@", c);c = nil;NSLog(@"%@", b);NSLog(@"%@", c);

在这里插入图片描述
可以看到在ARC环境下a,b,c都指向了对象,但是引用计数只有2,这是因为weak是指向对象的指针但并不持有对象,并不会使引用计数加1

当我们将weak修饰符改为strong时,就会出现如下结果

    id a = [[NSObject alloc] init];id __strong b = a;id c = a;NSLog(@"%lu", CFGetRetainCount((__bridge  CFTypeRef)a));NSLog(@"%lu", CFGetRetainCount((__bridge  CFTypeRef)c));a = nil;NSLog(@"%lu", CFGetRetainCount((__bridge  CFTypeRef)c));NSLog(@"%@", b);NSLog(@"%@", c);c = nil;NSLog(@"%@", b);NSLog(@"%@", c);

在这里插入图片描述

循环引用

内存管理中会发生循环引用的问题,此时就需要用到__weak修饰符
在这里插入图片描述

正确的内存释放过程
首先B对象是A对象的一个属性,也就是A持有B,现在要释放掉A,需要给A发送一个release消息,这时A的引用计数变为0,就要走delloc方法,delloc方法会对A所持有的全部对象发送release消息,当然也包括B,也就是对B进行release,此时B的引用计数也变为0,然后执行delloc,最后A与B都被释放掉了

- (void)dealloc {[_b release]; // 释放持有的 B 实例_b = nil;[super dealloc];
}

在这里插入图片描述
循环引用的产生:
解释:对象之间互相持有,形成闭环,导致谁也无法被正确释放
循环引用容易发生内存泄漏。所谓内存泄漏就是应当废弃的对象在超出其生存周期后继续存在。
在这里插入图片描述

过程:

  • a.例如我们现在想让A释放,也就是让B给A发送release消息,此时B的属性强持有A,所以需要B在delloc方法中对A进行release
  • b.我们想要让B执行delloc,就需要就持有B的A对象发送release消息给B
  • c.想要A发送release消息给B,就需要A执行delloc方法
  • d.想要A执行delloc方法就需要持有A的B对象发送release消息

如此循环往复,对象之间都在等对方给自己发送release消息,导致谁也无法执行,如此往复便造成了循环引用

当然循环引用并不只出现在变量中,还出现在协议与block中,后面在学习的过程中会专门写博客记录

接下来我们谈论一下如何解决这类问题

因为我们知道weak可以使变量取得但并不持有对象,也就是说不会增加对象的引用计数,我们将对象中的属性用weak修饰符修饰就可以解决这个问题
在这里插入图片描述

在这里插入图片描述

使用weak时因为变量不持有对象,因此不会造成相互引用,当对象释放后weak变量会自动置为nil,也避免了野指针的情况

#pragma mark 持有对象的弱引用 MRC 在MRC下,没有__weak这样的自动nil置化特性    使用weak持有某对象弱引用时,对象被废弃,弱引用变量自动只为nilid __weak obj1 = nil;{id __strong obj0 = [[NSObject alloc] init];obj1 = obj0;;NSLog(@"%@", obj1);}NSLog(@"%@", obj1);

在这里插入图片描述

__unsafe_unretained修饰符

__unsafe_unretained是一个不安全的所有权修饰符,在MRC下使用来避免循环引用
在这里插入图片描述

但是与weak相比,其会产生悬垂指针

因此我们在使用**__unsafe_unretained必须保证对象存在**

什么时候使用__unsafe_unretained

  • 其与weak相比,可能会有一些更好的性能,追求极致性能便可以使用__unsafe_unretained修饰
  • 以及在早版本的iOS中需要使用__unsafe_unretained来代替__weak.
  • 比如我们在访问单例或者全局变量时就可以使用这个修饰

__autoreleasing修饰符

ARC中不能使用autorelease方法以及NSAutoreleasePool类,但是实际上ARC有效时autorelease功能还是有作用的

  1. 指定“@autoreleasepol 块”来替代“NSAutoreleasePool 类对象生成、持有以及废弃”这一范围
@autoreleasepool{
id __autoreleasing obj = [[NSObject alloc] init];
}
  1. 为对象附加__autoreleasing修饰符代替autorelease方法,等价于在ARC无效时调用autorelease即将对象注册到autoreleasepool
    在这里插入图片描述
    但是我们一般不会显式地添加__autoreleasing,因为编译器会检查方法名是否以alloc/new/ copy/mutableCopy 开始,如果不是则自动将返回值的对象注册到autoreleasepool。
    例如:
@autoreleasepool f
id __strong obj = [NSMutableArray array];
}

访问附有__weak 修饰符的变量时,实际上必定要访问注册到autoreleasepool的对象

因为weak修饰符只持有对象的弱引用,因此访问引用对象时对象可能被遗弃。所以我们将对象注册到autoreleasepool可以确保对象存在
当将对象注册在autoreleasepool中,autoreleasepool会临时保留这个对象,直到作用域结束

另外在书上讲id *obj = id __autoreleasing *obj,以此类推NSObject **obj便成为了NSObject * _autoreleasing *obj,这里我们需要知道NSObject *__autoreleasing t1与NSObject __autoreleasing *t1有本质的不同:

  • 前者指向对象的对象会在被赋值时加入到自动释放池
  • 后者常在NSError错误处理中见到

在自动引用计数(ARC)管理的 Objective-C 环境中,当你使用双重指针(比如 NSError **error)作为方法参数时,ARC 会假定这个指针指向的对象是 __autoreleasing

总结来说,NSObject *__autoreleasing t2 是一个自动释放的对象指针,而 NSObject
__autoreleasing *t1 是指向一个自动释放对象指针的指针。

我们以一个代码例子来实验一下

@interface ViewController : UIViewController
@property (nonatomic, weak)NSObject *Obj1;
@property (nonatomic, weak)NSObject *Obj2;@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];[self test1];}- (void)test1 {NSLog(@"%@   %@", self.Obj1, self.Obj2);[self test2];NSLog(@"%@   %@", self.Obj1, self.Obj2);}- (void)test2 {NSObject *t1 = [[NSObject alloc] init];NSObject *__autoreleasing t2 = [[NSObject alloc] init];self.Obj1 = t1;self.Obj2 = t2;NSLog(@"%@   %@", self.Obj1, self.Obj2);}

在这里插入图片描述
这段代码中因为test2中,t1超出变量作用域,同时self.obj1是被weak修饰的,并不持有对象,对象超出作用域自动销毁,因此第三行输出null。
而t2由于使用了 __autoreleasing,它的生命周期被延长到当前的自动释放池结束

它的生命周期被延长到当前的自动释放池结束"这句话的含义是:

  • 使用__autoreleasing修饰的对象不会在创建它的作用域(通常是一个函数或@autoreleasepool块)结束时被立即释放。
  • 相反,这个对象会被自动添加到当前的Autorelease Pool中,延长了它的生命周期。
  • 直到当前的Autorelease Pool被销毁时,这个对象才会被最终释放。
@interface ViewController : UIViewController
@property (nonatomic, strong)NSObject *Obj1;
@property (nonatomic, strong)NSObject *Obj2;@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];[self test1];}- (void)test1 {NSLog(@"%@   %@", self.Obj1, self.Obj2);[self test2];NSLog(@"%@   %@", self.Obj1, self.Obj2);}- (void)test2 {NSObject *t1 = [[NSObject alloc] init];NSObject *__autoreleasing t2 = [[NSObject alloc] init];self.Obj1 = t1;self.Obj2 = t2;NSLog(@"%@   %@", self.Obj1, self.Obj2);}

在这里插入图片描述
而这段代码中obj用了strong修饰,即使t1,t2作为局部变量超出了作用域,但是self.Obj1仍然持有这个对象,因此这个对象并不会被销毁,因此其仍然存在

四、ARC规则

  • 不能使用retain/release/retainCount/autorelease
  • 不能使用NSAllocateObject/NSDeallocateObject
  • 必须遵守内存管理的方法名规则
  • 不要显式调用dealloc
  • 使用@autorelease块代替NSAutoreleasePool
  • 不能使用区域(NSZone)
  • 对象型变量不能作为C语言结构体的成员
  • 显式转换id和void*

不要显式调用dealloc

dealloc 方法在大多数情况下还适用于删除已注册的代理或观察者对象。
在这里插入图片描述

五、属性

在这里插入图片描述

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

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

相关文章

蓝桥杯--冶炼金属

目录 一、题目 二、解决代码 (1)版本一(报错:超时) 代码分析 (2)版本二(不会超时) 代码分析 (3)版本三(最终精简版)…

Python自学☞序列和索引的相关操作

一、基本概念 1、概念 序列是一个用于存储多个值的连续空间,每个值都对应一个整数的编号,称为索引 2、切片的语法结构 注:切片可以访问序列一定范围内的元素 序列[start:end:step] start-->切片的开始索…

Python数据分析-5

1.时间序列 2.pandas重采样 重采样:指的是将时间序列从一个频率转化为另一个频率进行处理的过程,将高频率数据转化为低频率数据为降采样,低频率转 化为高频率为升采样。 统计出911数据中不同月份电话次数的变化情况&#xff1a…

vue3中的文字滚动播报

vue3中的文字滚动播报 之前UI框架一直使用的elementPlus,有个需求,需要在页面上写个滚动播放新闻的功能,发现UI框架居然没有这个组件。花了一下午,在ChatGPT的帮助下,总算写成功了,先看最终展示效果 web页…

GPT-5:人工智能的下一个前沿即将到来

当我们站在人工智能新时代的门槛上时,GPT-5即将到来的呼声愈发高涨且迫切。作为革命性的GPT-3的继任者,GPT-5承诺将在人工智能领域迈出量子跃迁式的进步,其能力可能重新定义我们与技术的互动方式。 通往GPT-5之路 通往GPT-5的旅程已经标记着…

Unreal发布Android在刘海屏手机上不能全屏显示问题

Unreal 4.27发布Android在刘海屏手机上不能全屏显示问题 Android设置全屏刘海屏全屏设置4.27设置刘海屏在部分手机不能显示问题 Android设置全屏 AndroidManifest.xml文件配置 ...<activity android:name"com.epicgames.ue4.GameActivity" android:label"st…

给电脑加硬件的办法 先找电脑支持的接口,再买相同接口的

需求&#xff1a;我硬盘太小&#xff0c;换或加一个大硬盘 结论&#xff1a;接口是NVMe PCIe 3.0 x4 1.找到硬盘型号 主硬盘 三星 MZALQ512HALU-000L2 (512 GB / 固态硬盘) 2.上官网查 或用bing查 非官方渠道信息&#xff0c;不确定。

CompletableFuture原理与实践-外卖商家端API的异步化

背景 随着订单量的持续上升&#xff0c;美团外卖各系统服务面临的压力也越来越大。作为外卖链路的核心环节&#xff0c;商家端提供了商家接单、配送等一系列核心功能&#xff0c;业务对系统吞吐量的要求也越来越高。而商家端API服务是流量入口&#xff0c;所有商家端流量都会由…

【深度学习笔记】9_5 多尺度目标检测

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 9.5 多尺度目标检测 在9.4节&#xff08;锚框&#xff09;中&#xff0c;我们在实验中以输入图像的每个像素为中心生成多个锚框。这些…

springboot+vue学生选课系统 java+ssm+idea+_mysql

系统包含三种角色&#xff1a;管理员、老师、学生&#xff0c;系统分为前台和后台两大模块&#xff0c;主要功能如下。 ide工具&#xff1a;IDEA 或者eclipse 编程语言: java 学生网上选课系统可以实现教室管理&#xff0c;老师管理&#xff0c;课程管理&#xff0c;教学计划管…

微服务分布式springcloud研究生志愿填报辅助系统

本文讲述了研究生志愿填报辅助系统。结合电子管理系统的特点&#xff0c;分析了研究生志愿填报辅助系统的背景&#xff0c;给出了研究生志愿填报辅助系统实现的设计方案。 本论文主要完成不同用户的权限划分&#xff0c;不同用户具有不同权限的操作功能&#xff0c;在用户模块&…

AJAX 03 XMLHttpRequest、Promise、封装简易版 axios

AJAX 学习 AJAX 3 原理01 XMLHttpRequest① XHR 定义② XHR & axios 关系③ 使用 XHR④ XHR查询参数案例&#xff1a;地区查询&#xff08;URLSearchParams&#xff09;⑤ XHR数据提交 POST 02 PromisePromise 使用Promise - 三种状态案例&#xff1a;使用Promise XHR 获取…

电商场景下 ES 搜索引擎的稳定性治理实践

继上文在完成了第一阶段 ES 搜索引擎的搭建后&#xff0c;已经能够实现对千万级别的商品索引的读写请求的支持。目前&#xff0c;单机房读流量在 500&#xff5e;1000 QPS 之间&#xff0c;写流量在 500 QPS 左右。 但随着业务的发展&#xff0c;问题也逐渐开始暴露&#xff0…

Wmware安装Linux(centerOS、Ubuntu版本)

目录 1、安装wmware 2、center版本 3、ubuntu版本 1、安装wmware 此处不做展开。 2、center版本 需要提前下载的文件&#xff1a; 无图形化界面https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso 有图形化界面https://mirrors.a…

增删卜易——八宫六十四卦

之前看倪海厦的《天纪》笔记里面提到了六十四卦世应,觉得不知道这个世应是啥意思。很长时间就没看了,偶然间看到了张文江教授写的一本书《潘雨廷先生谈话录》提到了《卜筮正宗》,“卜筮最后的判断是非理性转义,其他一切都只是形式”,“明人的著作,从京氏易出,如今天几日…

STM32 学习12 输入捕获与触摸按键

STM32 学习12 输入捕获与触摸按键 一、输入捕获介绍1. 概念2. STM32F1 资源3. 捕获原理 二、输入捕获配置步骤1. 使能时钟、设置端口模式2. 初始化定时器3. 设置捕获参数4. 开启捕获和定时器中断&#xff08;溢出中断|更新中断&#xff09;6. 编写定时器中断服务函数7. 使能定时…

针对教育行业的网络安全方案有哪些

智慧校园”是教育信息化进入高级阶段的表现形式&#xff0c;比“数字校园”更先进。集体知识共融、共生、业务应用融合创新、移动互联网物联网高速泛在是其重要特征。特别是在互联网教育的大环境下&#xff0c;为了更好的发挥智慧化教学服务和智慧化教学管理功能&#xff0c;需…

node.js入门—day02

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;给自己一个梦想&#xff0c;给世界一个惊喜。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章目录 什么是单线程…

计算机服务器中了devos勒索病毒怎么解密,devos勒索病毒解密工具流程

随着网络技术的不断发展与更新&#xff0c;越来越多的企业利用网络开展了各项工作业务&#xff0c;网络也为企业提供了极大便利&#xff0c;大大提高了办公效率。但网络是一把双刃剑&#xff0c;企业的数据安全问题一直是企业关心的主要话题&#xff0c;近日&#xff0c;云天数…

InDesign 2024:创意不熄火,设计不止步mac/win版

InDesign 2024&#xff0c;不仅仅是一个设计软件更新&#xff0c;它更是设计界的一次革命性飞跃。这款全新的设计软件将为您打开前所未有的创意大门&#xff0c;让您在设计的海洋中畅游无阻。 InDesign 2024 mac/win版获取 InDesign 2024以其卓越的性能和稳定性&#xff0c;确…