ReactiveCocoa Weak-Strong Dance
RAC在应用中大量使用了block,由于Objective-C语言的内存管理是基于引用计数的,为了避免循环引用问题,在block中如果要引用self,需要使用@weakify(self)和@strongify(self)来避免强引用。 一、block的循环引用问题
- (void)loadView { [super loadView]; _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey" object:nil queue:nil usingBlock:^(NSNotification *note) { [self dismissModalViewControllerAnimated:YES]; }]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:_observer]; } 代码分析: 在上面代码中,我们添加向通知中心注册了一个观察者,然后在 dealloc 时解除该注册,一切看起来正常。但这里有两个问题: 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,显然其中存在循环引用。
小结: 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 { [super loadView]; __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]; [super dealloc]; } - (void)loadView { [super loadView]; __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。
译注:分析一下其中可能存在的 block 循环引用问题。 self --> RACObserver macro --> RACSubscriber instance --> block --> self. 假如不使用weakify/strongify 那么现实其中的循环引用导致 self 始终无法释放。
最后友情提示:在使用时应该注意block的嵌套层数,不恰当的滥用多层嵌套block可能给程序的可维护性带来灾难。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |