假设我在UIViewController
子类中有以下方法:
- (void)makeAsyncNetworkCall
{
[self.networkService performAsyncNetworkCallWithCompletion:^{
dispatch_async(dispatch_get_main_queue(), ^{
[self.activityIndicatorView stopAnimating];
}
});
}];
}
我知道块中self
的引用导致块保留UIViewController
实例。只要performAsyncNetworkCallWithCompletion
没有将块存储在NetworkService
的属性(或ivar)中,我是否认为没有保留周期?
我意识到上面的这个结构将导致UIViewController被保留,直到performAsyncNetworkCallWithCompletion
完成,即使它是由系统早先发布的。但它可能(甚至可能?)系统将取消分配我的UIViewController
(after the changes to the way iOS 6 manages a UIViewController
's backing CALayer
memory)?
如果有理由我必须做“弱自我/强自我舞蹈”,它会是这样的:
- (void)makeAsyncNetworkCall
{
__weak typeof(self) weakSelf = self;
[self.networkService performAsyncNetworkCallWithCompletion:^{
typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
[strongSelf.activityIndicatorView stopAnimating];
}
});
}];
}
但是我觉得这很难看,并且如果没有必要的话就想避免它。
答案 0 :(得分:29)
由于我相信您已正确诊断,因此在此方案中使用self
不一定会导致强大的参考周期。但是这将在网络操作完成时保留视图控制器,在这种情况下(如在大多数情况下),没有必要。因此,可能没有必要使用weakSelf
,但这样做可能是谨慎的。它最大限度地减少了意外强引用周期的可能性,并导致更有效地使用内存(一旦视图控制器被关闭就释放与视图控制器关联的内存,而不是在网络操作完成之后不必要地保留视图控制器)
不需要strongSelf
构造。你可以:
- (void)makeAsyncNetworkCall
{
__weak typeof(self) weakSelf = self;
[self.networkService performAsyncNetworkCallWithCompletion:^{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.activityIndicatorView stopAnimating];
});
}];
}
您只需要weakSelf
/ strongSelf
组合,其中有一个强大的参考(例如,您正在取消引用ivars)或者您需要担心竞争条件。这似乎不是这种情况。
答案 1 :(得分:6)
我认为问题在于networkService可能会对该块保持强引用。并且视图控制器可能具有对networkService的强引用。因此,VC-> NetworkService-> block-> VC的可能的循环可能存在。但是,在这种情况下,通常可以安全地假设块在运行后将被释放,在这种情况下循环被破坏。因此,在这种情况下,没有必要。
必要时,如果块未被释放。比方说,你没有一个在网络调用后运行一次的块,而是有一个用作回调的块。即networkService对象维护对该块的强引用,并将其用于所有回调。在这种情况下,块将具有对VC的强引用,这将创建一个强循环,因此首选弱引用。
答案 2 :(得分:3)
不,如果你的self.networkService不使用它作为块属性你应该没问题
答案 3 :(得分:0)
答案在这里并不那么简单。我同意@ Rob的回答,但需要补充说明:
__weak
被认为是一种安全的方式,因为它在释放时会使自己失去意义,这意味着如果在调用对象已经被释放时发生回调很久就会发生回调,由块引用,就像从堆栈中弹出UIViewController
。增加取消任何操作的可能性仅仅是一个卫生问题,也可能是资源问题。例如,您也可以取消NSURLConnection
,它不仅可以取消NSOperation
,还可以在回调阻止的方法中异步取消正在执行的任何内容。
如果允许self保留块,那么如果UIViewController
正在释放UINavigationController
之类的调用者对象并且块仍然保留它,则故事可能会有点复杂回电话。在这种情况下,将执行回调块并假设某些数据将根据其结果进行更改。这甚至可能是想要的行为,但在大多数情况下并非如此。因此,在这种情况下取消操作可能更为重要,通过从UINavigationControllerDelegate
作为关联对象或单例驻留在可变集合中的异步任务取消UINavigationController
方法非常明智。 / p>
当然,保存下注是第一个选项,但仅限于您在解除调用者对象后不希望异步操作继续的情况。