40

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

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

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

我意识到上面的这个结构会导致 UIViewController 被保留直到performAsyncNetworkCallWithCompletion完成,即使它被系统提前释放。但它有可能(甚至可能吗?)系统会完全取消分配 my (UIViewController iOS 6 管理 aUIViewController的后备CALayer内存的方式发生变化之后)?

如果有理由我必须做“weakSelf/strongSelf dance”,它看起来像这样:

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

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

4

4 回答 4

34

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

但是,不需要strongSelf构造。你可以:

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

您只需要weakSelf/strongSelf组合在对强引用至关重要(例如,您正在取消引用 ivars)或者您需要担心竞争条件的情况下。这似乎不是这里的情况。

于 2014-01-14T13:21:52.043 回答
8

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

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

于 2014-01-14T13:32:11.310 回答
3

不,如果您的 self.networkService 不将其用作块属性,您应该没问题

于 2014-01-14T13:07:56.487 回答
1

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

  1. __weak被认为是一种安全的方式,因为它在释放时将自身归零,这意味着如果调用对象已经释放时发生回调,则不会有异常,由块引用,就像UIViewController从堆栈中弹出一样。增加取消任何操作的可能性只是她的卫生问题,也许还有资源问题。例如,您也可以取消,NSURLConnection不仅NSOperation可以取消,还可以取消在回调阻塞的方法中异步执行的任何内容。

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

当然,保存赌注是第一个选项,但仅在您不希望在关闭调用方对象后继续异步操作的情况下。

于 2014-07-11T11:46:57.020 回答