Block的引用循环问题 (ARC non-ARC)
2010年WWDC发布iOS4时Apple对Objective-C进行了一次重要的升级:支持Block。说到底这东西就是闭包,其他高级语音例如Java和C++已有支持,第一次使用Block感觉满简单好用的,但是慢慢也遇到很多坑。本文聊聊ARC和non-ARC下Block使用中的引用循环问题,最近遇到了好几次这种问题,还是深入记录下。先来套题目热热身,貌似能够全部答对的人蛮少的
Block实现原理
首先探究下Block的实现原理,由于Objective-C是C语言的超集,既然OC中的NSObject对象其实是由C语言的struct+isa指针实现的,那么Block的内部实现估计也一样,以下三篇Blog对Block的实现机制做了详细研究:
- A look inside blocks: Episode 1
- A look inside blocks: Episode 2
- A look inside blocks: Episode 3
虽然实现细节看着头痛,不过发现Block果然是和OC中的NSObject类似,也是用struct实现出来的东西。这个是LLVM项目compiler-rt分析的block头文Block_private.h头文件中关于Block的struct声明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
我们发现Block_layout中也有一个isa指针,像极了NSobject内部实现struct中的isa指针。这里的isa可能指向三种类型之一的Block:
- _NSConcreteGlobalBlock:全局类型Block,在编译器就已经确定,直接放在代码段__TEXT上。直接在NSLog中打印的类型为__NSGlobalBlock__。
- _NSConcreteStackBlock:位于栈上分配的Block,即__NSStackBlock__。
- _NSConcreteMallocBlock:位于堆上分配的Block,即__NSMallocBlock__。
为什么会有这么多种类呢?首先来看全局类型Block,看例子:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
为什么addBlock中添加到array中的Block属于全局Block呢?因为它不需要运行时(Runtime)任何的状态来改变行为,不需要放在堆上或者栈上,直接编译后在代码段中即可,就像个c函数一样。这种类型的Block在ARC和non-ARC情况下没有差别。
这个Block访问了作用域外的变量d,在实现上就是这个block会多一个成员变量对应这个d,在赋值block时会将方法exmpale中的d变量值复制到成员变量中,从而实现访问。
1 2 3 4 5 6 7 |
|
如果要修改d呢?:
1 2 3 4 5 6 7 8 9 |
|
由于局部变量d和这个block的实现不在同一作用域,仅仅在调用过程中用到了值传递,所以不能直接修改,而需要加一个标识符__block int d = 5;
,那么block就可以实现对这个局部变量的修改了。如果是这种block标识的变量,在Block实现中不再是简单的一个成员变量,而是对应一个新的结构体表示这个block变量。block的本质是引入了一个新的Block_byref{$var_name}{$index}结构体,被block关键字修饰的变量就被放到这个结构体中。另外,block结构体通过引入Block_byref{$var_name}{$index}指针类型的成员,得以间接访问到Block的外部变量。这样对Block外的变量访问从值传递转变为引用,从而有了修改内容的能力。
正常我们使用Block是在栈上生成的,离开了栈作用域便释放了,如果copy一个Block,那么会将这个Block copy到堆上分配,这样就不再受栈的限制,可以随意使用啦。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
函数getBlock中声明并赋值的returnedBlock,一开始是在栈上分配的,属于NSStackBlock,如果是non-ARC情况下return这个NSStackBlock,那么其实已经被销毁了,在函数中example()使用时就会crash。如果是ARC情况下,getBlock返回的block会自动copy到堆上,那么block的类型就是NSMallocBlock,可以在example()中继续使用。要在Non-ARC情况下正常运行,那么就应该修改为:
1 2 3 4 5 6 7 |
|
Block中的循环引用问题
扯了这么多,回到Block的循环引用问题,由于我们很多行为会导致Block的copy,而当Block被copy时,会对block中用到的对象产生强引用(ARC下)或者引用计数加一(non-ARC下)。
如果遇到这种情况:
1 2 3 4 5 6 7 8 9 |
|
对象有一个Block属性,然而这个Block属性中又引用了对象的其他成员变量,那么就会对这个变量本身产生强应用,那么变量本身和他自己的Block属性就形成了循环引用。在ARC下需要修改成这样:
1 2 3 4 5 6 7 8 9 |
|
也就是生成一个对自身对象的弱引用,如果是倒霉催的项目还需要支持iOS4.3,就用__unsafe_unretained替代__weak。如果是non-ARC环境下就将__weak替换为__block即可。non-ARC情况下,__block变量的含义是在Block中引入一个新的结构体成员变量指向这个__block变量,那么__block typeof(self) weakSelf = self;
就表示Block别再对self对象retain啦,这就打破了循环引用。
转载于:https://www.cnblogs.com/yjg2014/p/5077566.html
Block的引用循环问题 (ARC non-ARC)相关推荐
- 李洪强iOS经典面试题36-简单介绍 ARC 以及 ARC 实现的原理
李洪强iOS经典面试题36-简单介绍 ARC 以及 ARC 实现的原理 问题 简单介绍 ARC 以及 ARC 实现的原理. 考查点 ARC 是苹果在 WWDC 2011 提出来的技术,因此很多新入行的 ...
- [Object-C]_[初级]_[关于块block的引用外部变量的规则]
场景 在开发 Object-C 程序时, 很多情况下会用到它的块 block 特性, 这个 block 其实就是 lambda 表达式. 这个 block 和 lambda有什么区别, 还有什么需要注 ...
- 防止iOS中私有属性在block中的循环引用
想看答案可以直接瞅瞅底下代码. 对于一般的@property修饰的属性我们可以使用__weak转换一下self来修饰 __weak typeof(self) weakSelf = self;//然后把 ...
- Copy(定义,特点,深复制,浅复制)(非ARC,ARC的运用范围)
什么是copy? Copy的字面意思是"复制","拷贝",是一个产生副本的过程. 作用:利用一个源对象产生一个副本对象. 特点: 1,修改源对象的属性和行为,不 ...
- iOS Block弱引用
先weak再strong.可以很好的管理Block内部对self的引用 常规写法 __weak typeof(self) weakSelf = self;self.Button.rac_command ...
- ESP32 LVGL8.1 ——arc 圆弧 (arc 19)
提示:本博客作为学习笔记,有错误的地方希望指正 文章目录 一.arc 简介 1.1概述 Overview 1.2部分和风格 Parts and Styles 1.3使用 Usage 1.3.1 值和角 ...
- linux怎么执行arc文件,arc文件扩展名,arc文件怎么打开?
.arc 文件类型1:Nintendo Archive File 文件说明:Archive file used by Nintendo games; contains game properties, ...
- Xcode非ARC项目转ARC,ARC项目中支持非ARC也就是共存
1. Xcode非ARC项目转ARC 选中工程>Edit > Refactor > Convert to Objective -C ARC 然后就是下一步,save保存 eable ...
- 百度地图得引用 循环打印坐标
map () {let that = this;//创建Map实例var map = new BMap.Map("XSDFXPage");// 初始化地图,设置中心点坐标var p ...
最新文章
- torch nll_loss
- 统计学要学的计算机课程有哪些,统计学专业主要课程学什么_课程设置安排及分类...
- 工作几年的感想(一)
- java中软填空面试题,通过这9个Java面试题,就可以入职华为啦
- 涨姿势 | 一文读懂备受大厂青睐的ClickHouse高性能列存核心原理
- 免费电子书:Azure Web Apps开发者入门
- [原創]全面的權限控制方法(功能權限+數據權限+特殊權限(行,列))
- hdfs java 权限管理,HDFS的权限管理
- python图片压缩算法_Optipng,jpegoptim应用,用python实现图片压缩,让你的网站变得更快...
- [C++11] 智能指针
- 你真的会玩SQL吗?透视转换的艺术
- Spark在Ubuntu中搭建开发环境
- 360极速浏览器插件不见了
- IDEA前进后退快捷键设置
- 关于用LaTeX写英文论文
- php 2038,php处理大于2038年以后日期的一种方法
- 阿里云Elasticsearch搜索
- 浏览器无法启动百度网盘应用的解决办法
- windows10 脚本获取超级管理员权限
- 昆仑通态mcgs通过西门子200PLC200smart通讯
热门文章
- 十年千篇!人脸识别相关技术最全论文合辑
- 深度学习(七十二)ssd物体检测
- Bezier(贝塞尔)曲线的轨迹规划在自动驾驶中的应用(一)
- Java日志框架-logback的介绍及配置使用方法(纯Java工程)
- Mysql 数据 导入 导出
- pdfbox java.lang.outofmemoryerror_java - PDFBox 2.0.1挂起渲染pdf页面 - 堆栈内存溢出
- 教育部计算机考研大纲,2018考研大纲从哪里看?
- 动物行为检测计算机视觉_基于红外热成像和计算机视觉的动物行为研究系统便是其中一例...
- php post请求 下载文件,POST请求 下载文件
- CountDownLatch/CyclicBarrie用法记录