在自UIViewController调用的非保留完成中引用self时,weakSelf / strongSelf舞真的有必要吗?

说我在UIViewController子类中有以下方法:

 - (void)makeAsyncNetworkCall { [self.networkService performAsyncNetworkCallWithCompletion:^{ dispatch_async(dispatch_get_main_queue(), ^{ [self.activityIndicatorView stopAnimating]; } }); }]; } 

我知道块内的self引用导致UIViewController实例被块保留。 只要performAsyncNetworkCallWithCompletion不会将该块存储在我的NetworkService的属性(或ivar)上,我是否认为没有保留周期?

我意识到上面的这个结构将导致UIViewController被保留,直到performAsyncNetworkCallWithCompletion完成,即使它是由系统提前发布的。 但它可能(甚至可能?)系统将释放我的UIViewController 在所有 ( iOS 6pipe理UIViewController的支持CALayer内存的方式更改后 )?

如果有一个原因,我必须做的“自我/自我舞蹈”,看起来是这样的:

 - (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]; } }); }]; } 

但是我觉得这很丑陋,如果没有必要,我想避免它。

正如我相信你正确诊断的那样,在这种情况下,使用self不一定会引起强烈的参考周期。 但是,这将在networking操作完成时保留视图控制器,在这种情况下(如在大多数情况下),不需要。 因此,可能没有必要使用weakSelf ,但可能谨慎。 它最大限度地减less了意外的强参考周期的机会,并导致更有效地使用存储器(一旦该视图控制器被解散,就释放与视图控制器相关联的存储器,而不是在networking操作完成之后不必要地保留视图控制器) 。

strongSelf ,我们并不需要strongSelf构造。 您可以:

 - (void)makeAsyncNetworkCall { __weak typeof(self) weakSelf = self; [self.networkService performAsyncNetworkCallWithCompletion:^{ dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf.activityIndicatorView stopAnimating]; }); }]; } 

你只需要weakSelf / strongSelf组合,在这个组合中,有一个强有力的参考(例如,你正在取消ivars)或者你需要担心竞争条件。 这似乎并不是这种情况。

我认为问题在于networkService可能会对该块保持强有力的参考。 而视图控制器可能对networkService有很强的参考。 所以VC-> NetworkService-> block-> VC可能存在循环。 然而,在这种情况下,通常假设块在运行之后将被释放,在这种情况下周期被破坏。 所以,在这种情况下,这是没有必要的。

如果该块没有被释放,则必要的地方。 说,而不是一个networking调用后运行一个块,你有一个块作为callback。 即networkService对象保持对该块的强引用并将其用于所有callback。 在这种情况下,该块将对VC有强烈的参考,这将创build一个强大的循环,所以弱参考是首选。

不,如果你的self.networkService不使用它作为块属性,你应该没问题

答案在这里并不那么简单。 我同意@ Rob的回答,但需要额外的解释:

  1. __weak被认为是一种安全的方式,因为它在释放的时候会自我释放,这意味着如果在调用对象已经被释放的时候,callback发生的时候没有exception,就像块被引用的UIViewController一样。 增加取消任何手术的可能性,仅仅是一个卫生问题,也可能是资源。 你可以,例如也只是取消NSURLConnection ,它不仅NSOperation可以被取消,你可以取消任何asynchronous执行的方法,在callback块的方法。

  2. 如果让self被block保留,那么如果像UIViewController这样的调用者对象被UINavigationController释放并且block仍然保留并且callback,那么故事会变得有点复杂。 在这种情况下,callback块将被执行,并假定一些数据将被其结果改变。 这可能甚至是想要的行为,但在大多数情况下并非如此。 因此,在这种情况下取​​消操作可能更为重要,通过取消驻留在UINavigationController作为关联对象或作为单例的可变集合中的asynchronous任务,使其在UINavigationControllerDelegate方法中非常明智。

当然,保存赌注是第一个选项,但是只有在您closures调用者对象之后不希望asynchronous操作继续的情况下。