一.对下图分析
block
机制:block
会把block
里面的代码块的所有强指针都强引用
self
:强指针
self
:间接引用block
处理办法:在block
模块里面写入
**定义一个weakSelf,self 的弱指针 **
typeof:自动识别参数类型
__weak typeof(self) weakSelf = self;
注意:
1.如果你的内存学的不好就在block
模块里面少用self
,容易造成循环引用
2.block尽量少使用下划线(_)直接访问成员属性,因为底层就是self.属性名
验证方式:(看看有没有打印)
/** * 如果一个对象,即将被销毁的时候,就会被调用 */ -(void)dealloc { NSLog(@"%s",__func__); }
二.举例
循环引用指两个对象相互强引用了对方,即retain了对方,从而导致谁也释放不了谁的内存泄露问题。如声明一个delegate时一般用assign而不能用retain或strong,因为你一旦那么做了,很大可能引起循环引用。在以往的项目中,我几次用动态内存检查发现了循环引用导致的内存泄露。 这里讲的是block的循环引用问题,因为block在拷贝到堆上的时候,会retain其引用的外部变量,那么如果block中如果引用了他的宿主对象,那很有可能引起循环引用,如: - (void)dealloc { NSLog(@"no cycle retain"); } - (id)init { self = [super init]; if (self) { #if TestCycleRetainCase1 //会循环引用 self.myblock = ^{ [self doSomething]; }; #elif TestCycleRetainCase2 //会循环引用 __block TestCycleRetain *weakSelf = self; self.myblock = ^{ [weakSelf doSomething]; }; #elif TestCycleRetainCase3 //不会循环引用 __weak TestCycleRetain *weakSelf = self; self.myblock = ^{ [weakSelf doSomething]; }; #elif TestCycleRetainCase4 //不会循环引用 __unsafe_unretained TestCycleRetain *weakSelf = self; self.myblock = ^{ [weakSelf doSomething]; }; #endif NSLog(@"myblock is %@", self.myblock); } return self; } - (void)doSomething { NSLog(@"do Something"); } int main(int argc, char *argv[]) { @autoreleasepool { TestCycleRetain* obj = [[TestCycleRetain alloc] init]; obj = nil; return 0; } }
经过上面的ARC环境测试发现,在加了__weak和__unsafe_unretained的变量引入后,TestCycleRetain方法可以正常执行dealloc方法,而不转换和用__block转换的变量都会引起循环引用。
但是实际情况是:
1)MRC情况下,用__block可以消除循环引用。
2)ARC情况下,必须用弱引用才可以解决循环引用问题,iOS 5之后可以直接使用__weak,之前则只能使用__unsafe_unretained了,__unsafe_unretained缺点是指针释放后自己不会置空。
示例代码:(关于使用block会防止循环引用的代码示例)
1)在ARC下,由于__block抓取的变量一样会被Block retain,所以必须用弱引用才可以解决循环引用问题,iOS 5之后可以直接使用__weak,之前则只能使用__unsafe_unretained了,__unsafe_unretained缺点是指针释放后自己不会置空。示例代码:
//iOS 5之前可以用__unsafe_unretained //__unsafe_unretained typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self; self.myBlock = ^(int paramInt) { //使用weakSelf访问self成员 [weakSelf anotherFunc]; };
2)在非ARC下,显然无法使用弱引用,这里就可以直接使用__block来修饰变量,它不会被Block所retain的,参考代码:
//非ARC __block typeof(self) weakSelf = self; self.myBlock = ^(int paramInt) { //使用weakSelf访问self成员 [weakSelf anotherFunc]; };