弹出ViewController时,停止执行GCD

时间:2015-05-07 04:43:31

标签: ios objective-c grand-central-dispatch

我的应用程序中有一个-[tableView reloadData]方法,为了加快执行速度,我已通过以下方法在GCD中调用它。

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{

    [tableView reloadData];
});    

但是当我弹出我的viewController时,应用程序崩溃了这条消息[SecondViewController numberOfSectionsInTableView:]: message sent to deallocated instance 0x7fe376206e10。我假设退出ViewController后[reloadData]仍在执行。我该如何停止执行?我应该把它变成NSOperation吗?如果是这样,我将如何做?

3 个答案:

答案 0 :(得分:3)

您的代码存在一些问题。以下是导致崩溃的事件序列

1)该块捕获tableView并使其保持活动状态。

2)然后你的视图控制器被pop,

取消分配

3)块执行,tableView调用它的数据源(你的视图控制器),现在已经解除分配。

你可以通过停止上面的#1或#3来解决这个问题。我建议#1。 (我在这里假设ARC)

__weak UITableView *weakTableView = tableView;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    [weakTableView reloadData];
});

如果这不起作用,其他一些东西可能会使tableView保持活跃状态​​。您应该调查究竟是做什么的,但您也可以通过阻止视图控制器dealloc方法中的#3来修复崩溃:

- (void)dealloc {
    self.tableView.dataSource = nil;
    self.tableView.delegate = nil;
}

答案 1 :(得分:0)

作为一个选项,您可以弱保留数据源并检查它:

__weak __typeof__(self) dataSource = self; // or whatever it is

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  if (dataSource!=nil)    
  {
    [weakTable reloadData];
  }
});

如果您持有数据源,将新的数据源设置为表视图并再次删除该数据源,则仍然存在非常不可能的崩溃,因此将其解除分配。

答案 2 :(得分:-1)

不幸的是,您无法停止GCD执行,但还有其他方法可以解决此问题。由于本主题中的主要问题是关于停止执行,我将使用NSOperation根据您的要求发布解决方案。

1-创建一个NSOperationQueue

NSOperationQueue *_myQueue;
_myQueue = [NSOperationQueue new];
_myQueue.name = @"com.my.queue";

2-从队列中重新加载您的表。 (我会使用块好吗?)

[_myQueue addOperationWithBlock:^{

    //your really expensive function
    //and your table reload call
    [tableView reloadData];
}];

3-现在您可以使用

取消执行
//maybe you will want to do this on viewDidDisappear
[_myQueue cancelAllOperations];

<强>更新

哎呀,我看到你正在推迟表重载调用,但是NSOperation没有延迟机制。要解决此问题,您可以使用

模拟延迟
[NSThread sleepForTimeInterval:1.5];

[tableView reloadData];内调用addOperationWithBlock:或继续使用GCD,然后更改tableView对weak的引用,以避免阻止保留tableView对象,像这样:

__weak __typeof__(tableView) weakTable = tableView;

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{

    //Now, if your table object was released at this point, the reloadData
    //will be ignored
    [weakTable reloadData];
});

希望它有所帮助...