Block 循环引用(中)
不会造成循环引用的block
大部分GCD方法
dispatch_async(dispatch_get_main_queue(), ^{
[self doSomething];
});
因为self并没有对GCD的block进行持有,没有形成循环引用。目前我还没碰到使用GCD导致循环引用的场景,如果某种场景self对GCD的block进行了持有,则才有可能造成循环引用。
block并不是属性值,而是临时变量
- (void)doSomething {
[self testWithBlock:^{
[self test];
}];
}
- (void)testWithBlock:(void(^)())block {
block();
}
- (void)test {
NSLog(@"test");
}
这里因为block只是一个临时变量,self并没有对其持有,所以没有造成循环引用
block使用对象被提前释放
有这种情况,如果不只是ClassA持有了myBlock,ClassB也持有了myBlock。

当ClassA被someObj对象释放后

此时,ClassA对象已经被释放,而myBlock还是被ClassB持有,没有释放;如果myBlock这个时被调度,而此时ClassA已经被释放,此时访问的ClassA将是一个nil对象(使用__weak修饰,对象释放时会置为nil),而引发错误。
另一个常见错误使用是,开发者担心循环引用错误(如上所述不会出现循环引用的情况),使用__weak。比如
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf doSomething];
});
因为将block作为参数传给dispatch_async时,系统会将block拷贝到堆上,而且block会持有block中用到的对象,因为dispatch_async并不知道block中对象会在什么时候被释放,为了确保系统调度执行block中的任务时其对象没有被意外释放掉,dispatch_async必须自己retain一次对象(即self),任务完成后再release对象(即self)。但这里使用__weak,使dispatch_async没有增加self的引用计数,这使得在系统在调度执行block之前,self可能已被销毁,但系统并不知道这个情况,导致block执行时访问已经被释放的self,而达不到预期的结果。
注:如果是在MRC模式下,使用__block修饰self,则此时block访问被释放的self,则会导致crash。
该场景下的代码
// ClassA.m
- (void)test {
__weak MyClass* weakSelf = self;
double delayInSeconds = 10.0f;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
NSLog(@"%@", weakSelf);
});
} // ClassB.m
- (void)doSomething {
NSLog(@"do something");
ClassA *objA = [[ClassA alloc] init];
[objA test];
}
运行结果
[:] do something
[:] self:(null)
解决方法:
对于这种场景,就不应该使用__weak来修饰对象,让dispatch_after对self进行持有,保证block执行时self还未被释放。
block执行过程中对象被释放
还有一种场景,在block执行开始时self对象还未被释放,而执行过程中,self被释放了,此时访问self时,就会发生错误。
对于这种场景,应该在block中对 对象使用__strong修饰,使得在block期间对 对象持有,block执行结束后,解除其持有。
- (void)testBlockRetainCycle {
ClassA* objA = [[ClassA alloc] init];
__weak typeof(objA) weakObjA = objA;
self.myBlock = ^() {
__strong typeof(weakObjA) strongWeakObjA = weakObjA;
[strongWeakObjA doSomething];
};
objA.objA = self;
}
注:此方法只能保证在block执行期间对象不被释放,如果对象在block执行执行之前已经被释放了,该方法也无效。
参考资料:block的循环引用问题
Block 循环引用(中)的更多相关文章
- iOS中Block循环引用的问题
说到循环引用问题,想必大家都碰到过吧,比如在使用Block的时候,使用__weakSelf来代替self解决等,但是对于这个,还是有不少可以探索的点,下面我就来说下,希望对大家有所帮助. 是否所有的B ...
- ios - block循环引用Demo示例
当实例变量中有了block属性,并且用copy来修饰,但是当调用block中的代码的时候,如果block中运用了self.属性的时候回造成循环引用. // // ViewController.h // ...
- iOS Block循环引用
在介绍block循环引用前我们先了解一下typeof. typeof是什么??? typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型. 它返回值是一个字符串,该字符串说明运算数的类 ...
- IOS block 循环引用的解决
在介绍block循环引用前我们先了解一下typeof. typeof是什么??? typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型. 它返回值是一个字符串,该字符串说明运算数的类 ...
- Block循环引用详解
前言 在项目中经常用到block,使用不当就很容易因为循环引用而造成内存泄漏.本文分析了block循环引用形成原因以及处理办法,如果有什么不对或者疑问请留言. 什么情况下block会造成循环引用 bl ...
- Block循环引用问题(Objective-c)
造成循环引用的简单理解是:Block的拥有者在Block作用域内部又引用了自己,因此导致了Block的拥有者永远无法释放内存,就出现了循环引用的内存泄漏 示例代码 @interface ObjTest ...
- Block循环引用问题研究
自从苹果在objc中添加Block功能支持以后已经过了很久.目前网上对于Block的使用有很多介绍.不过对于Block的内存管理问题,则是众说纷纭.再加上objc开始使用ARC以后,对于Block的内 ...
- ios block循环引用问题
ios开发中,开了ARC模式,系统自动管理内存,如果程序中用到了block就要注意循环引用带来的内存泄露问题了 这几天遇到一个问题,正常页面dismiss的时候是要调用dealloc方法的,但是我的程 ...
- Block 循环引用(上)
iOS的内存管理机制 Objective-C在iOS中不支持GC(垃圾回收)机制,而是采用的引用计数的方式管理内存. 引用计数:在引用计数中,每一个对象负责维护对象所有引用的计数值.当一个新的引用指向 ...
随机推荐
- mysql插入一条记录时有自增id怎么办
①可以把id的值设置为null或者0,这样子mysql都会自己做处理 ②手动指定需要插入的列,不插入这一个字段的数据!
- 【PyQt5-Qt Designer】QComboBox-下拉列表框
知识点: 1.QComboBox下拉列表框的一些常用方法 2.下拉列表框常用信号使用方法 案例:选中下拉框选项时触发信号 #[str] 表示comboBox中的选择框内容如A B C D 等 self ...
- 原生js可视加载图片、延迟加载、懒加载
<script> //既视加载//var oBtn = document.getElementsByTagName('button')[0];var aImages = document. ...
- mysql实时增量备份
采用binlog日志的好处 掌控所有更改操作,必要时可用于恢复数据 数据库主从复制的必要条件 [root@localhost~]# vim /etc/my.cnf [mysqld] .. .. log ...
- Python--共享变量
- 共享变量: 当多个线程同时访问一个变量的时候,会产生共享变量的问题 - 案例11 - 解决变量:锁.信号灯 - 锁(Lock): - 是一个标志,表示一个线程在占用一些资源 - 使用方法 - 上锁 ...
- 前端框架之Vue(8)-表单输入绑定
基础用法 你可以用 v-model 指令在表单 <input> . <textarea> 及 <select> 元素上创建双向数据绑定.它会根据控件类型自动选取正确 ...
- ls 命令查看文件时候,按修改时间倒序或升序排列
1,按照时间升序 命令:ls -lrt 详细解释: -l use a long listing format 以长列表方式显示(详细信息方式) -t sort by modification time ...
- ftp工具类
package com.ytd.zjdlbb.service.zjdlbb; import java.io.File;import java.io.FileInputStream;import jav ...
- Kubernetes总结
1.Kubernetes简介 在了解Kubernetes之前,我们有必要先简单了解一下传统的运维模式.在传统的项目架构中(单体or微服务),我们一般将项目打包为war或fatJar的方式进行部署. 在 ...
- 实习培训——Java多线程(9)
实习培训——Java多线程(9) 很适合新手 http://www.cnblogs.com/GarfieldEr007/p/5746362.html http://www.cnblogs.com/Ga ...