• [ios2]警告:Block的Retain Cycle的解决方法 【转】


    1. <span style="background-color: rgb(248, 248, 248); font-family: 'PT Sans', Geogia, Baskerville, 'Hiragino Sans GB', serif; ">警告:Captureing ‘self’ strongly in this block is likely to lead to a retain cycle</span>  

    一个使用Block语法的实例变量,在引用另一个实例变量的时候,经常会引起retain cycle。这个问题在使用ASIHTTPRequest的block语法的时候会时不时的碰到。这个问题困扰了我这个小白很久。终于有一天,在 Advanced Mac OS X Programming上,看到了这个问题的解决方案。

    先用代码描述一下症状:

    1. <span style="font-size:18px;">/* ViewController.h */   
    2. #import <UIKit/UIKit.h>  
    3.   
    4. typedef void (^ABlock)(void); //定义一个简单的Block  
    5.   
    6. @interface ViewController : UIViewController {  
    7.     NSMutableArray *_items;  
    8.     ABlock _block;  
    9. }  
    10.   
    11. @end  
    12.   
    13. /* ViewController.m */   
    14.   
    15. #import "ViewController.h"  
    16.   
    17. @implementation ViewController  
    18.   
    19. - (void)viewDidLoad  
    20. {  
    21.     [super viewDidLoad];  
    22.     // Do any additional setup after loading the view, typically from a nib.  
    23.     _items = [[NSMutableArray alloc] init];  
    24.     _block = ^{  
    25.         [_items addObject:@"Hello!"]; //_block引用了_items,导致retain cycle。  
    26.     };  
    27. }  
    28.   
    29. @end</span>  

    Xcode在编译以上程序的时候会给出一个警告:Captureing ‘self’ strongly in this block is likely to lead to a retain cycle。原因是_items实际上是self->items_block对象在创建的时候会被retain一次,因此会导致self也被retain一次。这样就形成了一个retain cycle。

    解决方法就是,创建一个本地变量blockSelf,指向self,然后用结构体语法访问实例变量。代码如下:

     

    1. __block ViewController *blockSelf = self;  
    2. _block = ^{  
    3.     [blockSelf->_items addObject:@"Hello!"];  
    4. };  

    这么修改之后,blockSelf是本地变量,是弱引用,因此在_blockretain的时候,并不会增加retain count,所以retain cycle就解除了,Xcode也不再出现警告了,问题解决。

    注:本文并非原创,详情请参阅Advanced Mac OS X Programming,第92页“Block Retain Cycles”。

     

     

    n manual reference counting mode, __block id x; has the effect of not retaining x. In ARC mode, __block id x; defaults to retaining x (just like all other values). To get the manual reference counting mode behavior under ARC, you could use __unsafe_unretained __block id x;. As the name __unsafe_unretained implies, however, having a non-retained variable is dangerous (because it can dangle) and is therefore discouraged. Two better options are to either use __weak (if you don’t need to support iOS 4 or OS X v10.6), or set the __block value to nil to break the retain cycle.

    The following code fragment illustrates this issue using a pattern that is sometimes used in manual reference counting.

    MyViewController *myController = [[MyViewController alloc] init…];
    // ...
    myController.completionHandler =  ^(NSInteger result) {
       [myController dismissViewControllerAnimated:YES completion:nil];
    };
    [self presentViewController:myController animated:YES completion:^{
       [myController release];
    }];

    As described, instead, you can use a __block qualifier and set the myController variable to nil in the completion handler:

    MyViewController * __block myController = [[MyViewController alloc] init…];
    // ...
    myController.completionHandler =  ^(NSInteger result) {
        [myController dismissViewControllerAnimated:YES completion:nil];
        myController = nil;
    };

    Alternatively, you can use a temporary __weak variable. The following example illustrates a simple implementation:

    MyViewController *myController = [[MyViewController alloc] init…];
    // ...
    MyViewController * __weak weakMyViewController = myController;
    myController.completionHandler =  ^(NSInteger result) {
        [weakMyViewController dismissViewControllerAnimated:YES completion:nil];
    };

    For non-trivial cycles, however, you should use:

    MyViewController *myController = [[MyViewController alloc] init…];
    // ...
    MyViewController * __weak weakMyController = myController;
    myController.completionHandler =  ^(NSInteger result) {
        MyViewController *strongMyController = weakMyController;
        if (strongMyController) {
            // ...
            [strongMyController dismissViewControllerAnimated:YES completion:nil];
            // ...
        }
        else {
            // Probably nothing...
        }
    };
  • 相关阅读:
    2.Redis常用命令
    1.CentOS安装Redis
    PAT 1127 ZigZagging on a Tree(30分)
    单链表上的基本操作
    求一个序列中的主元素
    PAT 1018 Public Bike Management(30分)
    PAT 1013 Battle Over Cities
    《算法笔记》题目分类
    PAT 1030 Travel Plan(30分)
    CentOS 安装 NET Core SDK 
  • 原文地址:https://www.cnblogs.com/jinjiantong/p/3172969.html
Copyright © 2020-2023  润新知