本文主要是介绍iOS之Block报错:capturing self strongly in this block is likely to lead to a retain cycle,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
原地址: http://blog.csdn.net/lvxiangan/article/details/50728577
1、被block引用的变量都会被自动retain一次 ,这样的话至少可以保证我们的调用是有效的。因为 block中的retain是隐式的 ,所以极易出现retain cycle的问题。
2、retain cycle ,翻译成中文大概叫保留环吧。比如A和B两个对象,A持有B,B同时也持有A,A只有B释放之后才有可能释放,同样B只有A释放后才可能释放,当双方都在等待对方释放的时候, retain cycle就形成了,结果是,两个对象都永远不会被释放,最终内存泄露。
3、__strong : 赋值给这个变量的对象会自动被retain一次,如果在block中引用它,block也会retain它一次。
4、__unsafe_unretained : 赋值给这个变量不会被retain,也就是说被他修饰的变量的存在不能保证持有对象的可靠性,它可能已经被释放了,而且留下了一个不安全的指针。不会被block retain。
5、__weak :类似于__unsafe_unretained,只是如果所持有的对象被释放后,变量会自动被设置为nil,这样更安全些,不过只在IOS5.0以上的系统支持,同样不会被block retain。
6、__block: 表示这个变量能在block中被修改(值修改,而不是修改对象中的某一个属性,可以理解为修改指针的指向)。 会被自动retain 。
被 __block 修饰的变量在块中保存的是变量的地址。(其他为变量的值)
先用代码描述一下症状:
-
- #import <UIKit/UIKit.h>
- typedef void (^ABlock)(void);
- @interface ViewController : UIViewController {
- NSMutableArray *_items;
- ABlock _block;
- }
-
- @end
-
-
- #import "ViewController.h"
- @implementation ViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- _items = [[NSMutableArray alloc] init];
- _block = ^{
- [_items addObject:@"Hello!"];
- };
- }
-
- @end
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,然后用结构体语法访问实例变量。代码如下:
- __block ViewController *blockSelf = self;
- _block = ^{
- [blockSelf->_items addObject:@"Hello!"];
- };
这么修改之后
,blockSelf是本地变量
,是弱引用,因此在_block被retain的时候,并不会增加retain count,所以retain cycle就解除了,Xcode也不再出现警告了,问题解决。
例子2:
- DoSomethingManager *manager = [[DoSomethingManager alloc] init];
- manager.complete = ^{
- [manager otherAction];
- [manager release];
- };
retain cycle 就这么形成了,即使调用了release,manager也不会释放,因为manager和block相互持有了。为了解除retain cycle的话,我们可以这样写:
- __block DoSomethingManager *manager = [[DoSomethingManager alloc] init];
- __weak DoSomethingManager *weakmanager = manager;
- manager.complete = ^{
- [weakmanager otherAction];
- };
终极解决方案:
- - (IBAction)onTest:(id)sender
- {
- BlockDemo *demo = [BlockDemo blockdemo];
-
- [demo setExecuteFinishedParam:^(BlockDemo * ademo) {
- if (ademo.resultCode == 200) {
- NSLog(@"call back ok.");
- }
- }];
-
- [demo executeTest];
- }
这篇关于iOS之Block报错:capturing self strongly in this block is likely to lead to a retain cycle的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!