block中如何避免循环引用
使用 weak–strong dance 技术
block 可以直接引用 self,但是要非常小心地在 block 中引用 self。因为在 block 引用 self,可能会导致循环引用。如下例所示:
- @interface KSViewController ()
- {
- id _observer;
- }
- @end
- @implementation KSViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
- KSTester * tester = [[KSTester alloc] init];
- [tester run];
- _observer = [[NSNotificationCenter defaultCenter]
- addObserverForName:@"TestNotificationKey"
- object:nil queue:nil usingBlock:^(NSNotification *n) {
- NSLog(@"%@", self);
- }];
- }
- - (void)dealloc
- {
- if (_observer) {
- [[NSNotificationCenter defaultCenter] removeObserver:_observer];
- }
- }
在上面代码中,我们添加向通知中心注册了一个观察者,然后在 dealloc 时解除该注册,一切看起来正常。但这里有两个问题:
1.) 在消息通知 block 中引用到了 self,在这里 self 对象被 block retain,而 _observer 又
retain 该 block的一份拷贝,通知中心又持有 _observer。因此只要 _observer 对象还没有被解除注册,block
就会一直被通知中心持有,从而 self 就不会被释放,其 dealloc 就不会被调用。而我们却又期望在 dealloc 中通过
removeObserver 来解除注册以消除通知中心对 _observer/block 的 retain。
2.) 同时,_observer 是在 self 所在类中定义赋值,因此是被 self retain 的,这样就形成了循环引用。
上面的过程 1) 值得深入分析一下:
苹果官方文档中对 addObserverForName:object:queue:usingBlock: 中的 block 变量说明如下:
The block is copied by the notification center and (the copy) held until the observer registration is removed.
因此,通知中心会拷贝 block 并持有该拷贝直到解除 _observer 的注册。在 ARC 中,在被拷贝的 block 中无论是直接引用 self 还是通过引用 self 的成员变量间接引用 self,该 block 都会 retain self。
这两个问题,可以用 weak–strong dance 技术来解决。该技术在 WWDC 中介绍过:2011 WWDC Session #322 (Objective-C Advancements in Depth)
- __weak KSViewController * wself = self;
- _observer = [[NSNotificationCenter defaultCenter]
- addObserverForName:@"TestNotificationKey"
- object:nil queue:nil usingBlock:^(NSNotification *n) {
- KSViewController * sself = wself;
- if (sself) {
- NSLog(@"%@", sself);
- }
- else {
- NSLog(@"<self> dealloc before we could run this code.");
- }
- }];
下面来分析为什么该手法能够起作用。
首先,在 block 之前定义对 self 的一个弱引用 wself,因为是弱引用,所以当 self 被释放时 wself 会变为 nil;然后在 block 中引用该弱应用,考虑到多线程情况,通过使用强引用 self 来引用该弱引用,这时如果 self 不为 nil 就会 retain self,以防止在后面的使用过程中 self 被释放;然后在之后的 block 块中使用该强引用 self,注意在使用前要对 self 进行了 nil
检测,因为多线程环境下在用弱引用 wself 对强引用 sself 赋值时,弱引用 wself 可能已经为 nil 了。
通过这种手法,block 就不会持有 self 的引用,从而打破了循环引用
block中如何避免循环引用的更多相关文章
- block(六)循环引用-b
在ARC与非ARC环境下对block使用不当都会引起循环引用问题,一般表现为,某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身,简单说就是self.theBloc ...
- block使用小结、在arc中使用block、如何防止循环引用
引言 使用block已经有一段时间了,感觉自己了解的还行,但是几天前看到CocoaChina上一个关于block的小测试主题: [小测试]你真的知道blocks在Objective-C中是怎么工作的吗 ...
- 关于Block的copy和循环引用的问题
http://blog.csdn.net/felix9/article/details/9619313 在实际开发中,发现使用Block有着比delegate和notification更简洁的优势.于 ...
- Block的copy和循环引用的问题
在实际开发中,发现使用Block有着比delegate和notification更简洁的优势.于是在目前的项目中大量的使用block. 在我的头文件我是这样声明使用block的. 我将block声明为 ...
- Block的使用及循环引用的解决
Block是一个很好用的东西,这篇文章主要来介绍:1.什么是Block?2.Block的使用?3.Block的循环引用问题及解决. 1.什么是Block? 说这个问题之前,我先来说一下闭包(Closu ...
- block的用法和循环引用
一.block在OC中的用法可以分为大概一下几种. 1>用于成员属性,保存一段代码,可以替代代理传值. 比如说,创建一个ViewController控制器,点击屏幕就跳转到ModalViewCo ...
- iOS - Block产生Memory Leaks循环引用导致的内存泄漏以及解决方案
在ARC(自动引用技术)前,Objective-c都是手动来分配释放 释放 计数内存,其过程非常复杂. ARC技术推出后,貌似世界和平了很多,但是其实ARC并不等同于Java或者C#中的垃圾回收,AR ...
- swift中闭包的循环引用
首先我们先创造一个循环引用 var nameB:(()->())? override func viewDidLoad() { super.viewDidLoad() let bu = UIBu ...
- 小解系列-自关联对象.Net MVC中 json序列化循环引用问题
自关联对象在实际开发中用的还是比较多,例如常见的树形菜单.本文是自己实际的一个小测试,可以解决循环引用对象的json序列化问题,文笔不好请多见谅,如有错误请指出,希望有更好的解决方案,一起进步. 构造 ...
随机推荐
- 线程隔离ThreadLocal
ThreadLocal是什么 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地 ...
- WCF传输图片解决方案
图片无法序列化后传输,但我们可以将图片转二进制字符串传输.然后在服务端将二进制字符串转图片. 将图片转字符串的例子: private byte[] BmpToJpegBuff(Image img) { ...
- Eclipse 常用快捷键
Ctrl + Shift + L : 可以查看快捷键方式 Ctrl + 1 : 快速修复 Ctrl + / : 注释当前行 Ctrl + D : 删除当前行 Shift + Enter : 可以在当 ...
- 写一个程序可以对两个字符串进行测试,得知第一个字符串是否包含在第二个字符串中。如字符串”PEN”包含在字符串“INDEPENDENT”中。
package lovo.test; import java.util.Scanner; public class Java { @param args public static void main ...
- The Managed Metadata Service or Connection is currently not available 分类: Sharepoint 2015-07-09 13:28 5人阅读 评论(0) 收藏
Does the following error message looks familiar to you? (When you go to Site Actions –> Site Sett ...
- 嵌入式 python异常except语句用法与引发异常 zz
http://blog.sina.com.cn/s/blog_8795b0970101dj0a.html
- C#遍历XML文件动态加载菜单
通过遍历XML文件动态加载菜单,顺便利用WebBrowser控件实现一个简单的桌面浏览器 效果如下: 代码如下: XMLFile1.xml <?xml version="1.0&quo ...
- java基础之 多态
在面向对象编程(Object-Oriented Programming, OOP)中,多态机制无疑是其最具特色的功能,甚至可以说,不运用多态的编程不能称之为OOP.这也是为什么有人说,使用面向对象语言 ...
- 几种通过JDBC操作数据库的方法,以及返回数据的处理
1.SQL TO String :只返回一个查询结果 例如查询某条记录的总数 rs = stmt.executeQuery(replacedCommand); if (rs ! ...
- centos7安装nginx
一般我们都需要先装pcre, zlib,前者为了重写rewrite,后者为了gzip压缩. 一:安装 pcre 1.下载地址:百度云盘 http://pan.baidu.com/s/1dFusO3v ...