zoukankan      html  css  js  c++  java
  • ReactiveCocoa Weak-Strong Dance

    AC在应用中大量使用了block,由于Objective-C语言的内存管理是基于引用计数的,为了避免循环引用问题,在block中如果要引用self,需要使用@weakify(self)和@strongify(self)来避免强引用。

    一、block的循环引用问题

    [objc] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. - (void)loadView  
    2. {  
    3.   [superloadView];  
    4.              
    5.   _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"  
    6.                                                                 object:nil  
    7.                                                                  queue:nil  
    8.                                                             usingBlock:^(NSNotification *note) {  
    9.       [self dismissModalViewControllerAnimated:YES];    
    10.   }];  
    11. }  
    12. - (void)dealloc  
    13. {  
    14.   [[NSNotificationCenter defaultCenter] removeObserver:_observer];  
    15. }  

    代码分析:

    在上面代码中,我们添加向通知中心注册了一个观察者,然后在 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,很漂亮的名字。其实现如下:

    [objc] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. - (void)dealloc  
    2. {  
    3.   [[NSNotificationCenter defaultCenter] removeObserver:_observer];  
    4. }  
    5.    
    6. - (void)loadView  
    7. {  
    8.   [superloadView];  
    9.              
    10.   __weak TestViewController *wself = self;  
    11.   _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"  
    12.                                                                 object:nil  
    13.                                                                  queue:nil  
    14.                                                             usingBlock:^(NSNotification *note) {  
    15.       TestViewController *sself = wself;  
    16.       [sself dismissModalViewControllerAnimated:YES];  
    17.   }];  
    18. }  
    在 block 使用 self 之前先用 __weak 修饰 self 创建一个 self 弱引用变量 ,然后在 block 中使用 self 之前先用 __strong 修饰创建一个 对该弱引用 self 的强引用,防止 self 被提前释放。

    这样的话就可以打破循环引用了。

    当然,__weak 和 __strong 只在 ARC 情形下有效;对于非 ARC ,就需要用到 __block 了,效果相同,如下:

    [objc] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. - (void)dealloc  
    2. {  
    3.   [[NSNotificationCenter defaultCenter] removeObserver:_observer];  
    4.   [_observer release];  
    5.    
    6.   [superdealloc];  
    7. }  
    8.    
    9. - (void)loadView  
    10. {  
    11.   [superloadView];  
    12.              
    13.   __block TestViewController *bself = self;  
    14.   _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"  
    15.                                                                 object:nil  
    16.                                                                  queue:nil  
    17.                                                                ngBlock:^(NSNotification *note) {  
    18.       [bself retain];  
    19.       [bself dismissModalViewControllerAnimated:YES];  
    20.       [bself release];  
    21.   }];  
    22. }  

    三、ReactiveCocoa中的Weak-Strong Dance

    例如:

    [objc] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. @weakify(self);  
    2. [RACObserve(self,photosArray) subscribeNext:^(id x){  
    3.     @strongify(self);  
    4.     [self.collectionView reloadData];  
    5. }];  

    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可能给程序的可维护性带来灾难。

     
     
  • 相关阅读:
    文件上传控件 jQueryFileUpload在 MVC3中的实现
    谈谈开心王国的用户注册页面
    一个个人网站如何融资一千万
    netTcpBinding三种方法实现调用函数
    MVC实现RadioButtonList
    网易盖楼回复的简易实现
    sqlserver复制表结构
    显示目录下所有文件列表
    Jira:用户权限设置
    C#:Socket通信
  • 原文地址:https://www.cnblogs.com/Jenaral/p/5249917.html
Copyright © 2011-2022 走看看