当弹出 ViewController 时停止执行 GCD
Stop execution of a GCD, when the ViewController is popped
我的应用程序中有一个 -[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
。我假设 [reloadData]
在我退出 ViewController 后仍在执行。我怎样才能停止它的执行?我应该把它变成一个 NSOperation 吗?如果可以,我该怎么做?
您的代码有几个问题。以下是导致崩溃的一系列事件
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 保持活动状态。您应该调查到底是什么在做,但您也可以通过阻止视图控制器中的 #3 dealloc
方法来修复崩溃:
- (void)dealloc {
self.tableView.dataSource = nil;
self.tableView.delegate = nil;
}
不幸的是,您无法停止 GCD 的执行,但还有另一种方法可以修复此错误。由于此线程中的主要问题是关于停止执行,我将 post 根据您的要求使用 NSOperation 解决方案。
1- 创建一个 NSOperationQueue
NSOperationQueue *_myQueue;
_myQueue = [NSOperationQueue new];
_myQueue.name = @"com.my.queue";
2- 从队列中重新加载 table。 (我会用积木好吗?)
[_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];
更新:
糟糕,我看到你在延迟 table 重新加载调用,但 NSOperation 没有延迟机制。要解决此问题,您可以使用
模拟延迟
[NSThread sleepForTimeInterval:1.5];
在 addOperationWithBlock:
内调用 [tableView reloadData];
之前或像现在一样继续使用 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];
});
希望对您有所帮助...
作为一个选项,您可以弱保留数据源并检查它:
__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];
}
});
仍然不太可能发生崩溃,如果您持有数据源,请将新的数据源设置到 table 视图并再次删除该数据源,因此它会被释放。
我的应用程序中有一个 -[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
。我假设 [reloadData]
在我退出 ViewController 后仍在执行。我怎样才能停止它的执行?我应该把它变成一个 NSOperation 吗?如果可以,我该怎么做?
您的代码有几个问题。以下是导致崩溃的一系列事件
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 保持活动状态。您应该调查到底是什么在做,但您也可以通过阻止视图控制器中的 #3 dealloc
方法来修复崩溃:
- (void)dealloc {
self.tableView.dataSource = nil;
self.tableView.delegate = nil;
}
不幸的是,您无法停止 GCD 的执行,但还有另一种方法可以修复此错误。由于此线程中的主要问题是关于停止执行,我将 post 根据您的要求使用 NSOperation 解决方案。
1- 创建一个 NSOperationQueue
NSOperationQueue *_myQueue;
_myQueue = [NSOperationQueue new];
_myQueue.name = @"com.my.queue";
2- 从队列中重新加载 table。 (我会用积木好吗?)
[_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];
更新:
糟糕,我看到你在延迟 table 重新加载调用,但 NSOperation 没有延迟机制。要解决此问题,您可以使用
模拟延迟[NSThread sleepForTimeInterval:1.5];
在 addOperationWithBlock:
内调用 [tableView reloadData];
之前或像现在一样继续使用 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];
});
希望对您有所帮助...
作为一个选项,您可以弱保留数据源并检查它:
__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];
}
});
仍然不太可能发生崩溃,如果您持有数据源,请将新的数据源设置到 table 视图并再次删除该数据源,因此它会被释放。