Capturing 'self' strongly in this block is likely to lead to retain cycle 解决方案

来源:互联网 发布:oa软件有哪些 编辑:程序博客网 时间:2024/05/14 10:38

笔者在使用AFNetworking作为第三方网络下载库时,遇XCode 提示如下的警告:


具体代码块如下:

1,创建了一个属性 

@property (nonatomic,strong) AFHTTPRequestOperation *operation;

2,在下载方法里面代码:

   NSString *urlStr = kPlatformtype_URL;    NSString *URL = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString: URL]];        _operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];    [_operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {                NSDictionary *resultDic = [NSJSONSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingMutableLeaves error:nil];        if ([[resultDic objectForKey:@"success"] boolValue]) {                        NSArray *arr = [resultDic objectForKey:@"result"];            for (NSDictionary *dic in arr) {                PlatformtypeModel *model = [[PlatformtypeModel alloc] init];                model.typeID = [dic objectForKey:@"typeID"];                model.typeName = [dic objectForKey:@"typename"];                [self.typeArr addObject:model]; //出现警告 Capturing 'self' strongly in this block is likely to lead to retain cycle            }                    }else{            NSString *errormsg = [resultDic objectForKey:@"success"];            NSLog(@"errormsg:%@",errormsg);        }            } failure:^(AFHTTPRequestOperation *operation, NSError *error) {        NSLog(@"Failure: %@", error);    }];    [_operation start];


分析原因,Block 在创建时候被 retain了一次,导致在块里面的self也被retain了一次,导致了循环引用,双方都无法释放,这个问题在笔者的另一篇介绍block的专题原创博客 http://blog.csdn.net/mapboo/article/details/23180405 中的第7点就已经提到了,可能大家说把这句代码改成 

[_typeArr addObject:model];
就好了,其实也不对,这里的_typeArr,也是用到self->typeArr,所以依然会警告循环引用,但是如果把
AFHTTPRequestOperation *operation 

写成局部变量,则可以完成可以,因为在方法结束后,该变量就自动释放,里面的self也就跟着释放了,所以不会造成内存泄露,为此,我们就参考我博客里面提到的第7点规则来修改源代码,附第7条内容:

7 ,从栈复制到堆过程中,容易引起循环引用,建议变量前面增加__weak 修饰符来避免,尤其在MRC下__block说明符被用来避免Block中的循环引用,这是由于Block从栈复制到堆,若Block使用的变量为附有__Block 说明符的id类型或对象类型的自动变量,不会被retain,否则会被retain,即两种方式,如 id _weak temp = self; 和 __block id temp = self; 来达到防止循环引用。

解决方案:

两种方式来修改:

 NSString *urlStr = kPlatformtype_URL;    NSString *URL = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];  //转码成UTF-8  否则可能会出现错误    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString: URL]];        //__block MenuViewController *meunVC = self; //第一种    MenuViewController __weak *meunVC = self; //第二种    _operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];    [_operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {                NSDictionary *resultDic = [NSJSONSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingMutableLeaves error:nil];        if ([[resultDic objectForKey:@"success"] boolValue]) {                        NSArray *arr = [resultDic objectForKey:@"result"];            for (NSDictionary *dic in arr) {                PlatformtypeModel *model = [[PlatformtypeModel alloc] init];                model.typeID = [dic objectForKey:@"typeID"];                model.typeName = [dic objectForKey:@"typename"];                [meunVC.typeArr addObject:model];            }                    }else{            NSString *errormsg = [resultDic objectForKey:@"success"];            NSLog(@"errormsg:%@",errormsg);        }            } failure:^(AFHTTPRequestOperation *operation, NSError *error) {        NSLog(@"Failure: %@", error);    }];    [_operation start];

第一种方式,在block块外对self 使用一个用__block修饰的临时变量来指向,关键字
__block

第二种方式,在block块外将self用一个显式的表明是弱引用的临时变量来指向,可以通过关键字

 __weak
注意,默认的对象修饰符都是关键字 
 __strong


只要通过这样对self一个弱引用的指向,就能避免循环引用,同时XCode也就不再报警告啦,问题得到顺利解决。


0 0
原创粉丝点击