Board logo

标题: Blocks笔记(6) [打印本页]

作者: look_w    时间: 2019-2-19 15:48     标题: Blocks笔记(6)

block的循环引用

block循环引用的例子:
例1:

    typedef void (^blk_t)(void);
     
    @interface MyObject : NSObject {
        blk_t blk_;
    }
    @end
     
    @implementation MyObject
     
    - (id)init {
        self = [super init];
        blk_ = ^{NSLog(@"self = %@", self);};
     
        return self;
    }
     
    - (void)dealloc {
        NSLog(@"dealloc");
    }
    @end

例2:

    @interface MyObject : NSObject {
        blk_t blk_;
        id obj_;
    }
    @end
     
    @implementation MyObject
     
    - (id)init {
        self = [super init];
        blk_ = ^{ NSLog(@"obj_ = %@", obj_); };
        return self;
    }
    ...
    ...
     
    @end

分析:

    两个例子中都是block语法赋值给了成员变量中,因此block语法生成的block从栈复制到堆,例1持有使用的self,例2持有成员变量间接持有self;因此self持有block,block持有self,这就形成了循环引用;

    解决循环引用可以通过三种方式:__weak,__unsafe_unretained以及__block来修饰; 因此例1中加入id __weak tmp = self; 例2中加入:id __weak obj = _obj;并替换block中的self 和成员变量_obj即可;
    而__block修饰避免循环引用的前提是block必须要执行,并且要在block 内将对象置为 nil ,否则还是会造成循环引用,因此可以通过 __block 变量去控制对象的生命周期;

    typedef void (^blk_t)(void);
     
    @interface MyObject : NSObject {
        blk_t  blk_;
    }
    @end
     
    @implementation MyObject
     
    - (id)init {
        self = [super init];
     
        __block id tmp = self;
        blk_ = ^{
                    NSLog(@"self = %@", tmp);
                    tmp = nil;
                };
     
        return self;
    }
     
    - (void)execBlock {
        blk_();
    }
     
    - (void)dealloc {
        NSLog(@"dealloc");
    }
     
    @end

    三种方式解决循环引用的原因:__weak和__unsafe_unretained修饰变量并不会持有对象,在不支持__weak的情况下可以使用__unsafe_unretained来修饰避免循环引用,而__block在 MRC 下,使用__block说明符也可以避免循环引用。因为当 block 从栈拷贝到堆时,__block对象类型的变量不会被 retain,没有 __block 说明符的对象类型的变量则会被 retian。正是由于 __block 在 ARC 和 MRC 下的巨大差异,我们在写代码时一定要区分清楚到底是 ARC 还是 MRC




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0