block循环引用原理

作者: 无边小猪 | 来源:发表于2016-09-27 11:42 被阅读248次

    在block中调用self就回造成循环引用?当然不是。要创造出一个循环引用的block需要两个条件:
    1、在block中引用了self
    2、对block做了copy操作

    例如:

    @interface testClass : NSObject
    @property(nonatomic,copy) Fun fun;
    @end
    ......
    -(void)testBlock
    {
        testClass *tctemp =  [[testClass alloc] init];
        self.tc = tctemp;
        [tctemp release];
        NSLog(@"a count %d",self.retainCount);
        void (^function)()=^(){
            self.name = @"hello";
        };
        function();
        NSLog(@"a count %d",self.retainCount);
    }
    

    打印结果:
    2016-09-27 10:03:58.131 test[4085:29450] a count 4
    2016-09-27 10:03:58.132 test[4085:29450] a count 4
    释放self所在类时dealloc并未被调用

    若代码略做修改

    @interface testClass : NSObject
    @property(nonatomic,copy) Fun fun;
    @end
    ......
    -(void)testBlock
    {
        testClass *tctemp =  [[testClass alloc] init];
        self.tc = tctemp;
        [tctemp release];
        NSLog(@"a count %d",self.retainCount);
        void (^function)()=^(){
            self.name = @"hello";
        };
        self.tc.fun = function;
        self.tc.fun();
        NSLog(@"a count %d",self.retainCount);
    }
    

    打印结果:
    2016-09-27 10:06:32.456 test[4350:31404] a count 4
    2016-09-27 10:06:32.459 test[4350:31404] a count 5
    释放self所在类时dealloc被调用

    从上述两段代码可以看出,若仅在block中调用self是并不足以导致循环引用的,而真正导致循环引用的是copy的执行,copy执行后self引用计数器加1,self被block强引用,造成循环引用问题。

    而解决该问题的方式是在MRC下定义:
    __block typeof(self) weakself =self;
    在ARC下定义:
    __weak typeof(self) weakself =self;

    在block循环引用的解决办法中weak-strong dance是比较特别的一个,该方法可以通过在执行block过程中持有self,block执行结束后释放block来解决一些问题。
    用法如下:

    NSLog(@"self:%ld", CFGetRetainCount((__bridge CFTypeRef)self));
    __weak typeof(self) weakSelf = self;
    NSLog(@"self:%ld", CFGetRetainCount((__bridge CFTypeRef)self)); void (^hellofun)()= ^{
            typeof(weakSelf) strongSelf = weakSelf;
            strongSelf;
            NSLog(@"self:%ld", CFGetRetainCount((__bridge CFTypeRef)strongSelf));
        };
    hellofun();
    NSLog(@"self:%ld", CFGetRetainCount((__bridge CFTypeRef)self));
    

    打印结果如下:
    2016-09-27 11:37:32.900 arctest[1128:943736] self:3
    2016-09-27 11:37:32.900 arctest[1128:943736] self:3
    2016-09-27 11:37:32.900 arctest[1128:943736] self:4
    2016-09-27 11:37:32.900 arctest[1128:943736] self:3
    上述打印结果中可以看出在hellfun()执行过程中短暂的强引用了self,而当hellofun()执行结束后,局部变量strongSelf被释放,引用计数减1,不再强引用self。
    此种方法可避免在block执行的过程中self被释放而引发的异常。如果block执行过程中self的释放将被推迟到block执行结束后。

    相关文章

      网友评论

        本文标题:block循环引用原理

        本文链接:https://www.haomeiwen.com/subject/ekecyttx.html