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

Rob*_*ins 39 objective-c uiviewcontroller ios objective-c-blocks retain-cycle

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

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

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

我意识到上面的这个结构将导致UIViewController被保留直到performAsyncNetworkCallWithCompletion完成,即使它是由系统早先发布的.但它可能(甚至可能吗?),系统会收回我的UIViewController 所有(更改到iOS 6的一个管理方式后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];
            }
        });
    }];
}
Run Code Online (Sandbox Code Playgroud)

但是我觉得这很难看,并且如果没有必要就想避免它.

Rob*_*Rob 30

由于我相信您正确诊断,self在这种情况下使用不一定会导致强大的参考周期.但是这将在网络操作完成时保留视图控制器,在这种情况下(如在大多数情况下),没有必要.因此,可能没有必要使用weakSelf,但可能谨慎这样做.它最大限度地减少了意外强引用周期的可能性,并导致更有效地使用内存(一旦视图控制器被关闭就释放与视图控制器关联的内存,而不是在网络操作完成之后不必要地保留视图控制器) .

但是,不需要strongSelf构造.您可以:

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

您只需要weakSelf/ strongSelf组合,这对于拥有强大的参考(例如,您正在解除引用ivars)或者您需要担心竞争条件至关重要.这似乎不是这种情况.

  • 顺便说一句,如果您的网络操作耗时(由于请求的大小或数量)并且您不希望它们在视图控制器被关闭后继续执行,除了"weakSelf"模式之外,您可能还会考虑使您的网络操作可取消,并让视图控制器取消任何待处理的请求.使用具有可取消的基于NSOperation`的请求的操作队列而不是GCD可以促进该过程. (6认同)

Abi*_*ern 7

我认为问题在于networkService可能会对块进行强有力的引用.并且视图控制器可能具有对networkService的强引用.因此可能存在VC-> NetworkService-> block-> VC 的可能循环.但是,在这种情况下,通常可以安全地假设块在运行后将被释放,在这种情况下循环被破坏.因此,在这种情况下,没有必要.

必要时,如果块未被释放.比方说,你没有一个在网络调用后运行一次的块,而是有一个用作回调的块.即networkService对象维护对块的强引用,并将其用于所有回调.在这种情况下,块将具有对VC的强引用,这将创建一个强循环,因此首选弱引用.