self 的循环引用

1.  直接在 block 里面使用关键词 self

 

//不会产生循环引用,只有 block 引用着 self
dispatch_block_t
completionBlock = ^{ NSLog(@"%@", self); } MyViewController *myController = [[MyViewController alloc] init...]; [self presentViewController:myController animated:YES completion:completionHandler];
 

 

2. 在 block 外定义一个 __weak 的 引用到 self,并且在 block 里面使用这个弱引用

// 循环引用,self 的属性引用 block ,block 引用着 self
self.completionHandler = ^{ NSLog(@"%@", self); }
// 解决方法
__weak typeof(self) weakSelf = self; self.completionHandler = ^{ NSLog(@"%@", weakSelf); }; MyViewController *myController = [[MyViewController alloc] init...]; [self presentViewController:myController animated:YES completion:self.completionHandler];

这个情况下 block 没有 retain 对象并且对象在属性里面 retain 了 block 。所以这样我们能保证了安全的访问 self。 问题是,它可能被设置成 nil 的。问题是:如何让 self 在 block 里面安全地被销毁。

 

3. 在 block 外定义一个 __weak 的 引用到 self,并在在 block 内部通过这个弱引用定义一个 __strong 的引用。

不管 block 是否通过属性被 retain ,这里也不会发生循环引用。如果 block 被传递到其他对象并且被复制了,执行的时候,weakSelf 可能被nil,因为强引用被赋值并且不会变成nil的时候,我们确保对象 在 block 调用的完整周期里面被 retain了,如果抢占发生了,随后的对 strongSelf 的执行会继续并且会产生一样的值。如果 strongSelf 的执行到 nil,那么在 block 不能正确执行前已经返回了。

__weak typeof(self) weakSelf = self;
myObj.myBlock =  ^{
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
        [strongSelf doSomething]; // strongSelf != nil
        // preemption, strongSelf still not nil(抢占的时候,strongSelf 还是非 nil 的)
        [strongSelf doSomethingElse]; // strongSelf != nil
    }
    else {
        // Probably nothing...
        return;
    }
};

 参考:https://github.com/oa414/objc-zen-book-cn

posted @ 2017-08-24 17:14  Rthena  阅读(203)  评论(0编辑  收藏  举报