Block 的循环引用

Block是在栈上生成的,因此通常使用copy方法把Block复制到堆上,避免Block被马上释放。spa

Block会对内部的变量造成强引用,而若是同时该变量又持有这个Block,就会致使循环引用而没法释放,从而致使内存泄露。code

最多见的就是self持有Block,而又在Block内部调用self的方法或属性,那selfBlock就会造成循环引用而没法释放。因为咱们习惯在dealloc中释放对象,可是即便在dealloc中将Block释放也没用,由于selfdealloc根本不会跑进去。好比:对象

1 self.MyBlock = ^void(){
2  
3   [self doSomething];
4 };

 

其实,最简单的解决方法就是在self的某个非dealloc方法中将Block主动释放,并在须要释放self以前调用这个方法,这样才能有效的解除引用。可是这种方法使用起来比较麻烦,并且很容易忘记调用。blog

因此咱们通常是在Block中使用弱引用的self。下面分别介绍ARCMRC中在Block中使用弱引用self的方法。内存

ARC

1 __weak typeof(self) weakSelf = self;
2  
3 self.MyBlock = ^void(){
4  
5 __strong typeof(self) strongSelf = weakSelf;
6  
7   [strongSelf doSomething];
8 };

这样作的好处是没必要在Block直接使用self,这样就不会对self进行强引用,只要self须要释放,self就会自动释放,Block也会自动释放。ARC中,进入Block前,须要使用__weakself进行弱引用,并在Block中使用__strongweakSelf进行强引用。开发

这样作的另外一个好处是,在ARC中使用__weak以后,若是self在某个地方被释放了,那weakSelf也会被自动置为nil,这样即便在Block中使用weakSelf,也不会访问错误。get

而在Block中使用__strong则是为了不在使用Block的过程当中self被释放致使访问出错。class

 

MRC


1
__block typeof(self) blockSelf = self; 2 3 self.MyBlock = ^void(){ 4 5   if (!malloc_zone_from_ptr(blockSelf)) 6   return; 7 8   __strong typeof(self) strongSelf = blockSelf; 9 10   [strongSelf doSomething]; 11 };

其实,MRC的基本思路和ARC是同样的。有两处不一样:变量

  1. MRC中使用__block而不是__weak进行弱引用,由于在ARC中使用__block会对该对象进行强引用。循环

  2. MRCBlock中使用malloc_zone_from_ptr()方法判断blockSelf是否已经被释放,由于MRC不会对已释放的对象自动置为nil


 

可见,不管是MRC仍是ARC,解决方法都是相似的。虽然Block的使用增长了简洁性和便利性,但使用Block的过程当中也要时刻注意避免内存泄露。

How Do I Declare A Block in Objective-C? 总结了声明Block的几种格式,在开发过程当中能够参考使用。

相关文章
相关标签/搜索