ReactiveCocoa Weak-Strong Dance
AC在应用中大量使用了block,由于Objective-C语言的内存管理是基于引用计数的,为了避免循环引用问题,在block中如果要引用self,需要使用@weakify(self)和@strongify(self)来避免强引用。
一、block的循环引用问题
- - (void)loadView
- {
- [superloadView];
- _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
- object:nil
- queue:nil
- usingBlock:^(NSNotification *note) {
- [self dismissModalViewControllerAnimated:YES];
- }];
- }
- - (void)dealloc
- {
- [[NSNotificationCenter defaultCenter] removeObserver:_observer];
- }
代码分析:
在上面代码中,我们添加向通知中心注册了一个观察者,然后在 dealloc 时解除该注册,一切看起来正常。但这里有两个问题:
这段代码中涉及到的对象包括:notificationcenter, _observer, block, self.
a) 在消息通知 block 中引用到了 self,所以这里 self 对象被 block retain;而 _observer 又对该 block 进行retain,通知中心 notificationcentre 又持有 _observer。因此只要 _observer 对象还没有被解除注册,block 就会一直被持有,从而 self 就不会被释放,那么 dealloc 就不会被调用。而我们却又期望在 dealloc 中通过 removeObserver 来解除注册以消除通知中心 notificationcenter 对 _observer 的 retain。
小结:notificationcenter --> _observer --> block --> self 只有在 self 释放,dealloc 调用的时候,notificationcenter 才会释放 _observer,显然其中存在循环引用。
b) 同时,_observer 是在 self 所在类中定义赋值,因此是被 self retain 的,这样就形成了循环引用。
小结: self --> _observer --> block --> self 显然这也是一个循环引用。
二、Weak-Strong Dance
对于在block中的retain cycle,在2011 WWDC Session #322 (Objective-C Advancements in Depth)有一个解决方案weak-strong dance,很漂亮的名字。其实现如下:
- - (void)dealloc
- {
- [[NSNotificationCenter defaultCenter] removeObserver:_observer];
- }
- - (void)loadView
- {
- [superloadView];
- __weak TestViewController *wself = self;
- _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
- object:nil
- queue:nil
- usingBlock:^(NSNotification *note) {
- TestViewController *sself = wself;
- [sself dismissModalViewControllerAnimated:YES];
- }];
- }
在 block 使用 self 之前先用 __weak 修饰 self 创建一个 self 弱引用变量 ,然后在 block 中使用 self 之前先用 __strong 修饰创建一个 对该弱引用 self 的强引用,防止 self 被提前释放。
这样的话就可以打破循环引用了。
当然,__weak 和 __strong 只在 ARC 情形下有效;对于非 ARC ,就需要用到 __block 了,效果相同,如下:
- - (void)dealloc
- {
- [[NSNotificationCenter defaultCenter] removeObserver:_observer];
- [_observer release];
- [superdealloc];
- }
- - (void)loadView
- {
- [superloadView];
- __block TestViewController *bself = self;
- _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
- object:nil
- queue:nil
- ngBlock:^(NSNotification *note) {
- [bself retain];
- [bself dismissModalViewControllerAnimated:YES];
- [bself release];
- }];
- }
三、ReactiveCocoa中的Weak-Strong Dance
例如:
- @weakify(self);
- [RACObserve(self,photosArray) subscribeNext:^(id x){
- @strongify(self);
- [self.collectionView reloadData];
- }];
RACObserver is a C macro that takes two parameters: an object and a key path on that object. It returns a signal whose values are sent whenever the key path’s value changes. A completion value is sent when the object, in this case self, is deallocated. --> ? We subscribe to this signal in order to reload our collection view whenever our photosArray property is changed.
译注:RACObserver 是一个宏定义,有两个参数:an object and a key path on that object。当 object key path value 变化时,就会返回一个 signal。
我们对这个 signal 进行订阅,一旦 photoArray 属性发送变化,返回signal,就可以 reload collection view。
The weakify/strongify dance is all too common in Objective-C under ARC.Weakify creates a new, weak variable assigned to self. Strongify then creates a new, strong variable in its scope assigned to the weak self. When strongify does this, it’s using what’s called a “shadow variable” – so named because the new, strong variable is called self, replacing the former strong reference to self.
Basically, the subscribeNext: block is going to capture self in its lexical scope, causing a reference cycle between self and the block. The block is strongly referenced by the return value of subscribeNext:, a RACSubscriber instance. This is then captured by the RACObserver macro, which will be automatically deallocated once its first parameter, self is deallocated. Without the weakify/strongify invocations, self would never be deallocated.
译注:分析一下其中可能存在的 block 循环引用问题。
self --> RACObserver macro --> RACSubscriber instance --> block --> self. 假如不使用 weakify/strongify 那么现实其中的循环引用导致 self 始终无法释放。
最后友情提示:在使用时应该注意block的嵌套层数,不恰当的滥用多层嵌套block可能给程序的可维护性带来灾难。
ReactiveCocoa Weak-Strong Dance的更多相关文章
- iOS开发笔记15:地图坐标转换那些事、block引用循环/weak–strong dance、UICollectionviewLayout及瀑布流、图层混合
1.地图坐标转换那些事 (1)投影坐标系与地理坐标系 地理坐标系使用三维球面来定义地球上的位置,单位即经纬度.但经纬度无法精确测量距离戒面积,也难以在平面地图戒计算机屏幕上显示数据.通过投影的方式可以 ...
- Swift中的Weak Strong Dance
亲爱的博客园的关注着博主文章的朋友们告诉你们一个很不幸的消息哦, 这篇文章将会是博主在博客园发表的最后一篇文章咯, 因为之后的文章博主只会发布到这里哦 http://daiweilai.github. ...
- nonatomic, retain,weak,strong用法详解
strong weak strong与weak是由ARC新引入的对象变量属性 ARC引入了新的对象的新生命周期限定,即零弱引用.如果零弱引用指向的对象被deallocated的话,零弱引用的对象会被自 ...
- OC中@property属性关键字的使用(assign/weak/strong/copy)
OC中@property属性关键字的使用(assign/weak/strong/copy) 一.assign 用于 ‘基本数据类型’.‘枚举’.‘结构体’ 等非OC对象类型 eg:int.bool等 ...
- NSString NSMutableString copy mutableCopy retain weak strong整合
copy retain assign的差别在于对象属性的set方法 NSString 与 NSMutableString NSString是不可变字符串对象,这句话的意思,结合代码: #import ...
- assign, retain, copy, weak, strong
一.assign, retain, copy 的区别(引用计数 RC reference count) 参考:IOS基础:retain,copy,assign及autorelease 1. 假设你用m ...
- 【整理】Object-C中的属性(Property)的Setter:assign,copy,retain,weak,strong之间的区别和联系
iOS编程过程中,经常看到一些属性前面有些修饰符,比如copy,retain等. 这些关键字,是Object-C语言中,对于Property的setter. Mac官网: The Objective- ...
- iOS开发 -------- Block技术中的weak - strong
一 Block是什么? 我们使用^运算符来声明一个Block变量,而且在声明完一个Block变量后要像声明普通变量一样,后面要加; 声明Block变量 int (^block)(int) = NULL ...
- OC weak strong __weak __strong copy retain assign nonatomic atomic等关键字的总结
weak和strong的区别: weak和strong)不同的是 当一个对象不再有strong类型的指针指向它的时候 它会被释放 ,即使还有weak型指针指向它. 一旦最后一个strong型指针离去 ...
- [转]iOS ARC机制 weak strong
写在开头 虽然距离WWDC2011和iOS 5已经快一年时间,但是很多开发者并没有利用新方法来提高自己的水平,这点在ARC的使用上非常明显(特别是国内,基本很少见到同行转向ARC).我曾经询问过一些同 ...
随机推荐
- 说说final关键字(好像有干货)
在java开发过程中,final是大家常用的关键字,无非就是用来修饰类,方法和变量,来表名类不能被继承,方法不会被覆盖,变量不能被改变,悄悄的说一句,private方法也隐式的final.通过一段时间 ...
- Linux中ls命令详解
ls命令是linux下最常用的命令之一,ls跟dos下的dir命令是一样的都是用来列出目录下的文件,下面我们就来一起看看ls的用法 英文全名:List即列表的意思,当我们学习某种东西的时候要做到知其所 ...
- input text中不能显示空格后的内容
<input type="text" value='' /> 即value=后面一定要用引号引起来,不然就会出现空格及其后内容不显示的问题
- masonry使用问题
2015年11月3日 coreData的学习练习中复习使用masonry自动布局 masonry自动布局发现问题: 两个控件的相对布局: 如果被参考对象用这个带anchor的属性,就会报这样一个错误: ...
- cout、cerr、clog
其实大家平常常会用的主要有三个:cout.cerr.clog,首先简单介绍下三者. 这三者在C++中都是标准IO库中提供的输出工具(至于有关的重载问题在此不讨论): cout:写到标准输出的ostre ...
- java方法:flush()
flush本意是冲刷,这个方法大概取自它引申义冲马桶的意思,马桶有个池子,你往里面扔东西,会暂时保存在池子里,只有你放水冲下去,东西才会进入下水道. 同理很多流都有一个这样的池子,专业术语叫缓冲区,当 ...
- oracle一次删除多张表
通过拼接sql语句来完成 例如有如下个表 想一次性删除,执行如下语句: select 'drop table '||table_name ||';' as dropsql from USER_TABL ...
- UVA 10308 Roads in the North
input u1 v1 w1 u2 v2 w2 ... un vn wn 1<=vi,ui<=n+1 /n output 距离最远的两个点的距离 做法:一颗全连通且只有一条路从一个顶点到达 ...
- 2014 Shanghai Invitation Contest
题目链接 http://acm.hdu.edu.cn/search.php?field=problem&key=2014%C9%CF%BA%A3%C8%AB%B9%FA%D1%FB%C7%EB ...
- Trie/Xor
题目链接 /*有一个数组a1,a2,a3--an.找到一个连续子段[l,r],使得al ^ al+1 ^--^ ar达到最大. 一般思路:维护前缀异或+暴力: for(int i=1;i<=n; ...