iOS开发超神学院iOS 开发每天分享优质文章将来跳槽用

36.block的循环引用分析

2016-10-27  本文已影响99人  IIronMan

一.对下图分析

block的循环应用问题

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];

 };

其他人的博客
1):http://my.oschina.net/u/1432769/blog/390401
2):https://www.mgenware.com/blog/?p=1493

上一篇 下一篇

猜你喜欢

热点阅读