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;
}
};