iOS之Block报错:capturing self strongly in this block is likely to lead to a retain cycle

我们经常在block使用中碰到:capturing self strongly in this block is likely to lead to a retain cycle。

重要法则:
block对于其变量都会形成强引用(retain),对于self也会形成强引用(retain),而如果self本身对block也是强引用的话,就会形成 强引用 循环,无法释放——造成内存泄露。
1)self会对自己的属性或函数进行持有。
2)block主函数体,用到了self所拥有的任何东西(self、self.属性、[self 函数] ),block就会对self进行持有。
3)如果1、2情况同时存在,就会出现retain cycle问题。因为1)很难做出改变,所以解决方法是对2进行改进。

如何避免?
1、简单判断:我一般重写dealloc方法,查看dealloc方法是否调用来判断是否有循环引用。
2、深层分析:根据上面法则来分析代码。


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 修饰的变量在块中保存的是变量的地址。(其他为变量的值)



使用__weak打破循环的方法只在ARC下才有效,在MRC下应该使用__block

先用代码描述一下症状:
/* ViewController.h */   
#import <UIKit/UIKit.h>  
typedef void (^ABlock)(void); //定义一个简单的Block  
@interface ViewController : UIViewController {  
    
    // self的属性
    NSMutableArray *_items;

    // 1、self的属性,换句话说,self持有block,即self对block具有强引用
    ABlock _block; 
}  
  
@end  
  
/* ViewController.m */   
#import "ViewController.h"  
@implementation ViewController  
- (void)viewDidLoad  
{  
    [super viewDidLoad];  
    _items = [[NSMutableArray alloc] init];  

    _block = ^{  
       
        // 2、_block内部用到了self的属性_items,换句话说,_block持有了self,导致retain cycle。  
        // 因为只要 block中用到了对象的属性或者函数,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];//[[BlockDemo alloc]init];  
      
    [demo setExecuteFinishedParam:^(BlockDemo * ademo) {  // 2、自动回调:把demo传入block函数主体,作为函数主体的局部变量
        // 3、在这里使用demo,不受外界影响
        if (ademo.resultCode == 200) {
            NSLog(@"call back ok.");  
        }  
    }];  
      
    // 1、先执行自定义XX操作,并把demo作为block参数,回调block
    [demo executeTest]; 
}  

自己写block时,如果是回调,比较喜欢把自身当作参数传到block中。这样其实是编译器给我们做了弱引用。因此不会产生循环引用。


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"divide and grow: capturing huge diversity in crowd images with incrementally" 是一个标题,该标题是基于一种方法或者技术,用于在人群图像中捕捉巨大的多样性。该方法通过逐步分割和增长的方式来实现。 在传统的人群图像处理中,通常会面临到一个挑战,即人群中的个体数量巨大且多样性丰富。这使得对整个人群图像进行全局处理变得困难。 "divide and grow"方法通过将人群图像分割成更小的区域,并在每个区域中逐步增加分析的粒度来解决这个问题。 首先,该方法会将人群图像划分成多个重叠的子区域。然后,对每个子区域进行单独的分析,以捕捉到区域内的个体。这种分割使得处理的任务更加可管理,同时也可以提高对于人群中不同个体的检测能力。接下来,"divide and grow"方法会逐步增加分析的粒度,即进一步细分每个子区域,以更准确地捕捉到更多的个体。 通过这种逐步分割和增长的方式,"divide and grow"方法可以较好地捕捉到人群图像中的巨大多样性。这种方法可以帮助在人群中准确地检测和识别各种不同类型的个体,例如不同年龄、性别、服装等。 总之,"divide and grow: capturing huge diversity in crowd images with incrementally"是一种用于处理人群图像中巨大多样性的方法。通过逐步分割和增长的方式,该方法可以有效地捕捉到人群中各种不同类型的个体。这种方法可以在人群图像处理和识别中具有广泛的应用潜力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值