在自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的回答,但需要额外的解释:
-
__weak
被认为是一种安全的方式,因为它在释放的时候会自我释放,这意味着如果在调用对象已经被释放的时候,callback发生的时候没有exception,就像块被引用的UIViewController
一样。 增加取消任何手术的可能性,仅仅是一个卫生问题,也可能是资源。 你可以,例如也只是取消NSURLConnection
,它不仅NSOperation
可以被取消,你可以取消任何asynchronous执行的方法,在callback块的方法。 -
如果让self被block保留,那么如果像
UIViewController
这样的调用者对象被UINavigationController
释放并且block仍然保留并且callback,那么故事会变得有点复杂。 在这种情况下,callback块将被执行,并假定一些数据将被其结果改变。 这可能甚至是想要的行为,但在大多数情况下并非如此。 因此,在这种情况下取消操作可能更为重要,通过取消驻留在UINavigationController
作为关联对象或作为单例的可变集合中的asynchronous任务,使其在UINavigationControllerDelegate
方法中非常明智。
当然,保存赌注是第一个选项,但是只有在您closures调用者对象之后不希望asynchronous操作继续的情况下。