Block的循环引用探究

Block属性修饰用copy 在将block由栈区 拷贝到堆区后block内部会自动产生对外界的强或弱引用
  • 具体是对外界产生强引用 还是弱引用 可根据以下原则判断:
如果[Block内部]使用[外界声明的强引用]访问[对象A],那么[Block内部]会产生一个[强引用]指向[对象A]
  • 如下图 block内部 使用外界声明的强引用p访问对象p的name属性 那么block内部会产生一个强引用指向对象p
  • 这样导致对象p对block强引用(copy)
    block内部又对 对象p产生了强引用


    Block的循环引用探究_第1张图片
    Snip20180718_1.png
如果[Block内部]使用[外界声明的弱引用]访问[对象A],那么[Block内部]会产生一个[弱引用]指向[对象A]
Person * p = [[Person alloc]init];
    p.name = @"Bulice";
    __weak Person * weakP = p;
    p.block = ^{
        NSLog(@"%@",weakP.name);
    };

block外部使用__weak
block内部使用__strong

 Person * p = [[Person alloc]init];
    p.name = @"Bulice";
    __weak Person * weakP = p;
    p.block = ^{
        NSLog(@"block1---%@",weakP.name);
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"block2---%@",weakP.name);
        });
    };
    p.block();
[4356:345984] block1---Bulice
[4356:345984] -[Person dealloc]
[4356:345984] block2---(null)
  • 对打印结果分析如下

由于Block1 和 Block2内部 都使用了外部的弱引用 所以Block1执行完之后 除了GCD的Block(GCD内部对延时Block有强引用)之外 剩下的对象都销毁了(局部变量)
这样就导致了延时Block里相当于 nil.name


RAC和YYKit中都有 Block外部使用弱引用 内部使用强引用的宏
他们为什么这么做
代码分析如下

- (void)viewDidLoad {
    [super viewDidLoad];
    Person * p = [[Person alloc]init];
    p.name = @"Bulice";
    __weak Person * weakP = p;
    p.block = ^{
        __strong Person * strongP = weakP;
        NSLog(@"block1---%@",strongP.name);
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"block2---%@",strongP.name);
        });
    };
    p.block();
    
}
 block1---Bulice
 block2---Bulice
 [Person dealloc]
  • block1引用外部的weakP是安全的
  • 在内部创建一个强指针去指向 person 对象,因为在内部声明变量,Block 是不会强引用这个对象的,这也就在避免了循环引用风险的同时,又创建出了一个强指针指向对象。
  • 之后再 Block2 来引用相对于它来说是外部的变量 strongP ,
  • 这时 Block2 会默认创建出来一个强引用来引用 p 对象,
  • 当block1的作用域结束之后 strongP 会跟着被销毁,内存中就仅剩下了Block2 强引用着 p 对象 所以p的属性值在block2执行时 可以访问到。

鉴于能力一般 水平有限 理解有误之处 深望不吝指出 阿门

你可能感兴趣的:(Block的循环引用探究)