如何处理解除分配的块引用对象

时间:2014-02-15 22:43:53

标签: objective-c uiviewcontroller automatic-ref-counting objective-c-blocks

考虑执行此操作的UIViewController子类(使用ARC):

- (void)viewDidLoad {
    __weak id wself = self;
    dispatch_async(backgroundQueue, ^{
        longRunningOperation();
        dispatch_async(mainQueue, ^{
            [wself updateView];
        });
    });
}

问题

  1. 如果视图控制器在块仍在执行时deallocs会发生什么?
  2. 如果视图控制器在运行时deallocs,我怎么能让块立即停止执行?

4 个答案:

答案 0 :(得分:1)

如果您需要支持取消,则NSOperation/NSOperationQueue更易于使用。

如果对象被释放,那么在大多数情况下它应该没有问题,因为在nil上调用方法是noop。但是,如果您使用任何直接的ivar访问(self->myIvar),那么您可能会遇到崩溃,因为您将取消引用nil。解决这个问题的一种方法是在对对象执行任何操作之前获得强引用:

- (void)viewDidLoad
{
  [super viewDidLoad];

  __weak __typeof(self) weakSelf = self;
  dispatch_async(backgroundQueue, ^{
    longRunningOperation();

    dispatch_async(mainQueue, ^{
      __typeof(weakSelf) strongSelf = weakSelf;
      strongSelf->myIvar;
    });

  });
}

答案 1 :(得分:0)

在此代码中使用wself可能允许在longRunningOperation仍在执行时取消分配视图控制器。在这种情况下,我不认为传递弱自我是必要的,因为没有机会进行涉及块的循环引用。

就中断执行而言,最好的办法是在ViewDidDisappear中设置一个标志,使视图不再可见,并在执行updateView之前检查该标志。

答案 2 :(得分:0)

检查this SO question,这里有一个很好的答案,详细描述了GCD缺少取消功能。

除此之外,如果你尝试执行这段代码并在块执行时检查wselfself的值(另外,在检查自己的时候注释掉自己),你会看到wself变为nilself仍有值..所以我认为你在这里避免直接引用self是正确的。如果您同时检查同一个区块中的wselfself,则wself仍会有值。因此,如果您在块中直接引用self,则此块可以基本上保持wself更长时间。因此,使用wself将确保您不会无意中使事物保持活动的时间长于预期,因此选择器实际上不会做任何事情。

因此,您可以在执行时检查块中nil是否已成为nil,或者您可以依靠Objective-C在向{{1}传递消息时悄然无效(只要它不是一个无法识别的选择器)。

答案 3 :(得分:0)

如果您需要取消某些操作,请使用NSOperation和NSOperationQueue进行更好的编程。这将允许您取消应与视图一起取消分配的操作