block(六)循环引用-b
在ARC与非ARC环境下对block使用不当都会引起循环引用问题,一般表现为,某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身,简单说就是self.theBlock = ^(void){[self dosomething];或者self.otherVar = XXX;或者_otherVar = ...};block的这种循环引用会被编译器捕捉到并及时提醒,那要如何避免呢,我在这里做了个demo测试。
直接看demo
#import "ViewController.h"
#define CJSUPARC 1
typedef void(^myBlock)(void);
@interface ViewController ()@property (nonatomic, copy)myBlock theBlock; @end @implementation ViewController - (void)dealloc { #if CJSUPARC [super dealloc]; #else #endif NSLog(@"ViewController dealloc"); } - (void)viewDidLoad { [super viewDidLoad]; #if CJSUPARC __block typeof(self) wSelf = self; NSLog(@"%@",@(self.retainCount)); myBlock block = ^(void){ NSLog(@"%@",@(wSelf.retainCount)); NSLog(@"%@.block init",[wSelf.class description]); }; self.theBlock = [[block copy] autorelease]; if (self.theBlock) { self.theBlock(); } #else // __block typeof(self) wSelf = self; // __unsafe_unretained typeof(self) wSelf = self; __weak typeof(self) wSelf = self; myBlock block = ^(void){ NSLog(@"%@.block init",[wSelf.class description]); }; self.theBlock = [block copy]; if (self.theBlock) { self.theBlock(); } #endif } @end
MRC模式下运行
2016-01-09 23:50:33.993 CJBlockDemo[52536:2193676] self.retainCount = 6
2016-01-09 23:50:33.994 CJBlockDemo[52536:2193676] self.retainCount = 6
2016-01-09 23:50:33.994 CJBlockDemo[52536:2193676] ViewController.block init
2016-01-09 23:50:40.437 CJBlockDemo[52536:2193676] ViewController dealloc
可以看到使用__block能够避免引起循环引用的问题ARC模式下运行
使用__block
2016-01-09 23:50:33.994 CJBlockDemo[52536:2193676] ViewController.block init 虽然编译器警告是没有了,但ViewController却没有执行dealloc函数,说明在arc中__block还是会引起retain。
使用__unsafe_unretained
使用__weak
2016-01-09 23:50:33.994 CJBlockDemo[52536:2193676] ViewController.block init 2016-01-09 23:50:40.437 CJBlockDemo[52536:2193676] ViewController dealloc
都可以避免循环引用的问题,但由于前者是unsafe的,会造成野指针问题,所以尽量少用unsafe_unretained关键字
另外在多线程环境下(block中的wSelf有可能被析构的情况下),需要先将self转为strong指针,避免在运行到某个关键步骤时self对象被析构。
可参考AFNetworking代码:
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { __strong __typeof(weakSelf)strongSelf = weakSelf; strongSelf.networkReachabilityStatus = status; if (strongSelf.networkReachabilityStatusBlock) { strongSelf.networkReachabilityStatusBlock(status); } };
- 第一行:__weak __typeof(self)weakSelf = self;
为防止callback内部对self强引用,weak一下。
其中用到了__typeof(self),这里涉及几个知识点:
- __typeof、__typeof__、typeof的区别
恩~~他们没有区别,但是这牵扯一段往事,在早期C语言中没有typeof这个关键字,__typeof、__typeof__是在C语言的扩展关键字的时候出现的。
typeof是现代GNU C++的关键字,从Objective-C的根源说,他其实来自于C语言,所以AFNetworking使用了继承自C的关键字。 - 对于老的LLVM编译器上面这句话会编译报错,所以在很早的ARC使用者中流行__typeof(&*self)这种写法,原因如下
大致说法是老LLVM编译器会将__typeof转义为 XXX类名 *const __strong的__strong和前面的__weak关键字对指针的修饰又冲突了,所以加上&*对指针的修饰。
第三行:__strong __typeof(weakSelf)strongSelf = weakSelf;
self转回strong了,这里__typeof()里面写的是weakSelf,里面写self也没有问题,因为typeof是编译时确定变量类型,所以这里写self 不会被循环引用。第四、五、六行,如果不转成strongSelf而使用weakSelf,后面几句话中,有可能在第四句执行之后self的对象可能被析构掉,然后后面的StausBlock没有执行,导致逻辑错误。
最后第五行,使用前对block判空。
原文链接:https://www.jianshu.com/p/a87ed8a4363a =========================看法分割线===============
是否所有的Block中,使用self 都会导致循环引用?
系统自带Block不会发生循环引用
如图,使用系统自带的UIView 的Blcok,控制器能被销毁-->说明没有发送循环引用。
原理: UIView的调用的是类方法,当前控制器不可能强引用一个类 ,所以循环无法形成 --> 动画block不会造成循环引用的原因。
所以通过实践得出第一个结论--> 并不是所有的Block中使用self,都会导致循环引用!
问题二:面试官问:那除了系统自带的方法中的Block,你在其他Block中使用self 会导致循环引用吗? -->可答:AFN框架!
最常用的数据请求框架-- AFNetWorking框架的Block是否会强引用?
AFN的Block是否会导致循环引用测试
如上图所示,在AFN的 block { xxx self.view } 使用self,并不会导致循环引用!
原理:AFN无循环是因为绝大部分情况下,你的网络类对象是不会被当前控制器引用的,这时就不会形成引用环。(查阅资料得知)
小tips:也可能AFN底层有自己做了操作,这里没探究到AFN框架底层,仅知道AFN不会造成循环引用。
那什么情况下会导致循环引用呢? --> 自定义Block
自定义Block中使用self
添加 viewDidLoad 提示框-->每次进入都打印viewDidLoad,可以确定是否离开视图控制器-->如果是,但是没有调用dealloc --> 循环引用
循环引用
这时候,我们发现循环引用发生了!所有我们答道:“我们在实际开发中,使用自定义Block,在Block { xxx }中使用self,导致了循环引用 ”
循环引用导致的原因: 相互强指向
循环引用原因
如何解决-->使用weakSelf,这个解决方法估计没见过一百次的,都不算是真正参加过iOS面试的。
----------------------------- 华丽分割线--------------------------------------
一个大写的excuse me 写脸上,49行都报警告了,而且提示可能发送循环引用,这你都能因为这样导致循环引用??这面试官如果知道这个,应该不会这么友好的放过你吧?
由于现在学iOS的太多了,所有可能面试官如果对于循环引用比较了解的话,并不会因为我们回答了上面两个问题就放过我们~他可能会接着问:那如果是我们自己写的Block,(非系统和AFN),在Block中使用self,是否一定会发生循环引用~
探究四:自定义Block是否一定会发生循环引用?
在其他控制器声明一个强指向的Block
调用Blcok
执行效果
如图:发现oneVC被销毁了,说明,自己定义的Block,里面使用了self,并不一定会发生循环引用!
原理:block --> 强指向了self,但是self,并没有指向Block!-->并没有一个 self.block
或者 成员变量 @property block ,所有Block并没有被强指向-->没有发送循环引用!
-->Tips:循环引用发生的条件就是持有这个block的对象,被block里边加入的对象持有。
逼格出现了!!华丽分割线! 既然系统的Block、AFN、都不会发生循环引用,自定义Block又有这么明显的提示-->实际开发中不会遇到循环引用??
---------------------------------高逼格分割线-----------------------------------------
实际开发中:使用通知(NSNotifation),调用系统自带的Block,在Block中使用self --> 会发生循环引用。
通知的接收方法
现在iOS的通知已经比较好用了,如图第二个方法,我最常用的,特别方便,不需要写@selector(方法)+ 调用,直接写在Block中,就可以实现接收通知之后实现的代码。
twoVC发送通知 --> 给oneVC
oneVC 接收通知
使用通知-发生循环引用
如图!这才是实际开发中-->真正有可能发生循环引用的地方!确实也是在通知的Block,但是这次的循环引用并没有提示,而且也确实发生了 --> 这才是真正告诉面试官:我们做过有实际开发,并且是在真实的开发环境中遇到了-->真正的循环引用!!
解决办法-->weakSelf!
参考链接 http://www.jb51.net/article/108171.htm
block(六)循环引用-b相关推荐
- Block 的循环引用
Block是在栈上生成的,所以一般使用copy方法把Block复制到堆上,避免Block被立刻释放. Block会对内部的变量形成强引用,而如果同时该变量又持有这个Block,就会导致循环引用而无法释 ...
- Block的循环引用详解
1.首先我们创建了一个网络请求工具类 然后storyboard里面去创建了一个导航控制器 并且把它设置为初始控制器 然后拖入一个bar button --show--到自带的控制器 这个时候运行 ...
- Block的循环引用
2019独角兽企业重金招聘Python工程师标准>>> 在ios常见的循环引用中曾经提到过block: 看看上面最基本的block循环应用,self包含block,block包含了s ...
- ios开发 循环引用 检测_iOS开发——Block引起循环引用的解决方案
[目前总结了一下,在iOS平台容易引起循环引用的几个场景:一.parent-child模式二.block(编译器会提示警告)三.NSTimer] up vote 0 down vote favorit ...
- Block 本质、实现原理、内存管理、循环引用、__block等
一.Block介绍 1.1概念: 将函数及其执行上下文封装起来的对象 底层用struct实现 1.2block实现原理: a .新建项目 代码放入file.m中 b.打开终端cd到项目目录下 c.敲c ...
- iOS开发笔记(二):block循环引用
写这篇文章的缘由是第一次面试时被问到了block循环引用的问题,当时回答的不是很好,首先要明确的是,block是否用copy修饰决定不了循环引用的产生,在此再一次进行补强,有不对的地方还请多多指教. ...
- Block循环引用问题(Objective-c)
造成循环引用的简单理解是:Block的拥有者在Block作用域内部又引用了自己,因此导致了Block的拥有者永远无法释放内存,就出现了循环引用的内存泄漏 示例代码 @interface ObjTest ...
- ios block常见的错误(二)——循环引用
2019独角兽企业重金招聘Python工程师标准>>> 这篇博文继续block的常见错误--循环引用. 循环引用是很多初学者不能察觉的,其产生的原因,是block中的代码会对对象进行 ...
- 和block循环引用说再见
to be block? or to be delegate? 这是一个钻石恒久远的问题.个人在编码中暂时没有发现两者不能通用的地方,习惯上更偏向于block,没有什么很深刻的原因,只是认为block ...
- iOS循环引用问题集合、内存泄漏、僵尸对象、代码静态分析
内存泄漏:https://my.oschina.net/llfk/blog/1031291 内存泄漏监测自动化:http://www.cocoachina.com/articles/18490 fac ...
最新文章
- 相机标定:(1)相机模型
- 保存和加载pytorch模型
- APL开发日志--2012-11-08
- 企业网站标题优化要学会运用技巧和方法
- zookeeper平滑升级_zookeeper从3.4.8升级到3.4.14
- java url 上传文件_Java使用HttpURLConnection上传文件(转)
- 如何测量代码运行时间
- 2020年最受关注的前100 家互联网公司
- Centos6.4安装jdk
- oracle内连接时列的值是null,Oracle SQL - 比较空值时的JOIN性能
- OpenvSwitch readme faq
- 深度学习8-常用评估函数与自定义评估函数
- Atitti html5 h5 新特性attilax总结
- 西威变频器avo下载调试资料_免费下载 |《西门子全集成自动化技术》,很全很详细...
- 2020软考软件设计师--基础知识实战培训视频-任铄-专题视频课程
- 【ArcGIS】道路中心线提取、河道中心线的提取
- 三个因素剖析质量流量计读数不准,应对故障更轻松
- 如何在 SAP UI5 应用里显示 PDF 文件试读版
- Redis4.0、5.0、6.0、7.0特性整理(持续更新)
- 哥德尔不完全性定理:现代数学的边界