• block中如何避免循环引用


    使用 weak–strong dance 技术

    block 可以直接引用 self,但是要非常小心地在 block 中引用 self。因为在 block 引用 self,可能会导致循环引用。如下例所示:

    1. @interface KSViewController ()  
    2. {  
    3.     id _observer;  
    4. }  
    5.   
    6. @end  
    7.   
    8. @implementation KSViewController  
    9.   
    10. - (void)viewDidLoad  
    11. {  
    12.     [super viewDidLoad];  
    13.     // Do any additional setup after loading the view, typically from a nib.  
    14.       
    15.     KSTester * tester = [[KSTester alloc] init];  
    16.     [tester run];  
    17.       
    18.     _observer = [[NSNotificationCenter defaultCenter]  
    19.                  addObserverForName:@"TestNotificationKey"  
    20.                  object:nil queue:nil usingBlock:^(NSNotification *n) {  
    21.                      NSLog(@"%@", self);  
    22.                  }];  
    23. }  
    24.   
    25. - (void)dealloc  
    26. {  
    27.     if (_observer) {  
    28.         [[NSNotificationCenter defaultCenter] removeObserver:_observer];  
    29.     }  
    30. }  


    在上面代码中,我们添加向通知中心注册了一个观察者,然后在 dealloc 时解除该注册,一切看起来正常。但这里有两个问题:
        1.) 在消息通知 block 中引用到了 self,在这里 self 对象被 block retain,而 _observer 又 retain 该 block的一份拷贝,通知中心又持有 _observer。因此只要 _observer 对象还没有被解除注册,block 就会一直被通知中心持有,从而 self 就不会被释放,其 dealloc 就不会被调用。而我们却又期望在 dealloc 中通过 removeObserver 来解除注册以消除通知中心对 _observer/block 的 retain。
        2.) 同时,_observer 是在 self 所在类中定义赋值,因此是被 self retain 的,这样就形成了循环引用。
    上面的过程 1) 值得深入分析一下:
    苹果官方文档中对 addObserverForName:object:queue:usingBlock: 中的 block 变量说明如下:

    The block is copied by the notification center and (the copy) held until the observer registration is removed.
    因此,通知中心会拷贝 block 并持有该拷贝直到解除 _observer 的注册。在 ARC 中,在被拷贝的 block 中无论是直接引用 self 还是通过引用 self 的成员变量间接引用 self,该 block 都会 retain self。
    这两个问题,可以用 weak–strong dance 技术来解决。该技术在 WWDC 中介绍过:2011 WWDC Session #322 (Objective-C Advancements in Depth)

    1. __weak KSViewController * wself = self;  
    2.     _observer = [[NSNotificationCenter defaultCenter]  
    3.                  addObserverForName:@"TestNotificationKey"  
    4.                  object:nil queue:nil usingBlock:^(NSNotification *n) {  
    5.                      KSViewController * sself = wself;  
    6.                      if (sself) {  
    7.                          NSLog(@"%@", sself);  
    8.                      }  
    9.                      else {  
    10.                          NSLog(@"<self> dealloc before we could run this code.");  
    11.                      }  
    12.                  }];  

    下面来分析为什么该手法能够起作用。
        首先,在 block 之前定义对 self 的一个弱引用 wself,因为是弱引用,所以当 self 被释放时 wself 会变为 nil;然后在 block 中引用该弱应用,考虑到多线程情况,通过使用强引用 self 来引用该弱引用,这时如果 self 不为 nil 就会 retain self,以防止在后面的使用过程中 self 被释放;然后在之后的 block 块中使用该强引用 self,注意在使用前要对 self 进行了 nil 检测,因为多线程环境下在用弱引用 wself 对强引用 sself 赋值时,弱引用 wself 可能已经为 nil 了。
        通过这种手法,block 就不会持有 self 的引用,从而打破了循环引用

    技术改变世界,成就人生辉煌!
  • 相关阅读:
    gitlab文件夹的权限不要随便给777
    记python版本管理--pyenv
    centos7上基于kubernetes的docker集群管理
    centos下修改docker连接docker_host默认方式为tls方式
    微信公众帐号开发之一(java)
    java抓取12306火车余票信息
    对Word2Vec的理解
    软件工程课程助教总结
    2017面向对象程序设计(Java)第十七周助教工作总结
    2017面向对象程序设计(Java)第十三周助教工作总结
  • 原文地址:https://www.cnblogs.com/wuhanpjf/p/4601762.html
Copyright © 2020-2023  润新知