美文网首页
探秘ios中block的循环引用问题

探秘ios中block的循环引用问题

作者: blocky | 来源:发表于2017-02-28 11:33 被阅读225次

    hello,小伙伴们!
    ios中自从引入了block,代理就在慢慢淡出我们的视野,那么block的使用大家都了解吗?它的循环引用机制大家都了解吗?接下来我们就来聊聊这个话题.

    一,介绍下简单block的写法.

    //a,typedef 定义下的block写法
    typedef void(^cusBlock)();
    @property (copy , nonatomic)  cusBlock block;
    
    //b,直接属性定义下的block写法
    @property (copy , nonatomic)  void (^customBlock)();
    //还有很多写法,大家可以参考其它牛人的写法,这里就不做介绍了.
    

    二,执行block代码块(customBlock)

     self.customBlock = ^(){
            self.name = @"lili";
            NSLog(@"执行了block块的方法");
            
        }
        }
    touchesBegan后
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        
        if (self.customBlock) {
            self.customBlock();
        }
        
    }
    输出结果:2017-02-27 19:30:46.815 text[15115:303861] 执行了block块的方法
    

    三,block循环引用的结论

    //先说结论,后面再来分析
     如果 [block内部] 访问了 [外部强引用] 对象A ,那么 [block内部] 会自动产生一个 [强引用引用] 对象A;
    
     如果 [block内部] 访问了 [外部弱引用] 对象A ,那么 [block内部] 会自动产生一个 [弱引用引用] 对象A;
    

    四,分析循环引用,验证结论

    a,上述代码强引用的示意图

    block强引用示意图.png

    这样系统会抛出一个⚠️错误

    强引用警告示意图.png

    执行完block代码后

    block执行完成后强引用示意图.png

    这个提示告诉我们,block内部出现了循环引用(有强迫症的最好解决下,免得越积越多).

    b,解决办法,大家都知道的弱引用就可以完美的解决问题了.示意图如下

    block弱引用示意图.png

    c,特殊情况

    @interface BLPerson : NSObject
    @property(copy, nonatomic) NSString *name;
    @property (copy , nonatomic)  void (^customBlock)();
    @end
    #import "BLPerson.h"
    
    - (void)viewDidLoad{
       [super viewDidLoad];
       self.view.backgroundColor = [UIColor whiteColor];
       BLPerson *p = [[BLPerson alloc]init];
       __weak typeof(p)weakp = p;
       p.name = @"jack";
       p.customBlock = ^(){
           dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
               weakp.name = @"lili";
               NSLog(@"%@==执行了block块的方法",weakp.name);
           });
       };
       if (p.customBlock) {
           p.customBlock();
       }
    }
    
    运行结果:2017-02-28 11:17:23.519 text[4118:80908] (null)==执行了block块的方法
    weakp.name =null,这是为什么了,在block里面我明明已经将 weakp.name = @"lili"赋值了啊.
    

    经过分析这是因为,在执行dispatch_after这个block中代码的时候,由于weakp是弱引用,在这个时间差之间weakp已经被释放了,weakp为nil,意味着nil.name就没意义了.

    解决办法:在customBlock里面用一个强引用在引用weakp就行了;

     p.customBlock = ^(){ 
            BLPerson *p1 = weakp;
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                p1.name = @"lili";
                NSLog(@"%@==执行了block块的方法",p1.name);
            });
        };
    输出结果:2017-02-28 11:26:41.679 text[4280:84156] lili==执行了block块的方法;这个时候P1.name是有值的;
    ps:在block里面定义的属性是不会造成强引用的;
    

    本章总结:
    请大家牢记这两个结论,理解透了没有block会阻碍你前进的步伐.

    如果 [block内部] 访问了 [外部强引用] 对象A ,那么 [block内部] 会自动产生一个 [强引用引用] 对象A;
    
     如果 [block内部] 访问了 [外部弱引用] 对象A ,那么 [block内部] 会自动产生一个 [弱引用引用] 对象A;
    

    建议以后block里面如果没有特殊要求,建议都写成弱引用,避免造成自己都发现不了的bug.本文,如有误之处,请大家多多指教,我一定虚心学习,希望同大家共同进步.

    相关文章

      网友评论

          本文标题:探秘ios中block的循环引用问题

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