NSOperationQueue 阻塞 UITableView
NSOperationQueue blocks UITableView
以下代码是我公司的另一名员工编写的,但我现在必须解决性能问题...
方法deleteObjectAndAllDependencies
从我们的SQLite数据库中删除项目和相关数据...
tableView 仍然不可用,但一切都已执行。我怎样才能加快这个过程?不使用功能。
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
if ([[SARAM RAM] selectedProjektIndex] == indexPath.row) [[SARAM RAM] setSelectedProjektIndex:0];
NSBlockOperation *start = [NSBlockOperation blockOperationWithBlock:^{
[[SAAufmassProject popFromDatabaseForGUID:[SARAM projektPool][indexPath.row]] deleteObjectAndAllDependencies];
[[self projectData] removeObjectAtIndex:indexPath.row];
}];
NSBlockOperation *refresh = [NSBlockOperation blockOperationWithBlock:^{
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
[self dataHasBeenDeleted];
}];
[refresh addDependency:start];
[[NSOperationQueue currentQueue] addOperation:start];
[[NSOperationQueue currentQueue] addOperation:refresh];
}
}
这段代码很好奇。它创建两个同步操作,使一个依赖于另一个。然后它继续将这些操作添加到当前队列(主队列!)。这有点低效并且无法实现任何性能优势。更糟糕的是,看起来有人有野心通过采用异步模式使这段代码响应更快,但并没有完全实现这个目标。 (这可能表明存在一些更深层次的体系结构问题使这变得困难。)
撇开这一点,您可能想要的是在更新模型对象和主线程中的 UI 时触发数据库的异步更新:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
if ([[SARAM RAM] selectedProjektIndex] == indexPath.row) [[SARAM RAM] setSelectedProjektIndex:0];
// get reference to the guid
NSString *guid = [SARAM projektPool][indexPath.row]];
// perform the deletion in some background queue
[self.databaseQueue addOperationWithBlock:^{
[[SAAufmassProject popFromDatabaseForGUID:guid] deleteObjectAndAllDependencies];
}];
// meanwhile, back on the ranch, we'll update the table view
[[self projectData] removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self dataHasBeenDeleted];
}
}
事实是,这提出了几个问题:
您的 SQLite 实现是否支持来自后台线程的更新?许多简单的实现都不能正确处理这个问题。
projektPool
使用与 projectData
相同的索引,这让我很紧张。是deleteObjectAndAllDependencies
更新前者,而后者是在这个方法中更新。我怀疑这会是个问题。
我想知道 popFromDatabaseForGUID
、deleteObjectAndAllDependencies
、projektPool
和 projectData
之间存在更深层次的相互依赖关系。我还想知道这些是否真的是线程安全的(例如,当这些东西在后台运行时调用 cellForRowAtIndexPath
时,模型和数据库是否处于一致状态)?
最重要的是,就我之前的观点而言,现有代码表明存在早期的并发处理尝试,我敢打赌,存在一些更深层次的架构问题阻碍了这一努力。问题是我们这里没有足够的东西来诊断更深层次的问题(我怀疑设计太复杂了,无法在这样的论坛中有效地传达)。
暂时假设 (a) 确实存在更深层次的架构问题; (b) 此代码的重构超出您的预期,您可能需要检查代码以查看是否有任何性能改进的战术机会。例如,如果 deleteObjectAndAllDependencies
正在执行大量单独的 SQL 语句来更新数据库,您是否使用事务来加快速度?使用 SQLite,会对性能产生巨大影响。
最重要的是,我可能会通过 "Instruments" 中的 "Time Profiler" 工具(包括 "Record Waiting Threads" 选项)来 运行 这段代码,并追踪性能的来源问题。看看是否有一些 SQL 相关的战术机会(例如交易、索引等)。
以下代码是我公司的另一名员工编写的,但我现在必须解决性能问题...
方法deleteObjectAndAllDependencies
从我们的SQLite数据库中删除项目和相关数据...
tableView 仍然不可用,但一切都已执行。我怎样才能加快这个过程?不使用功能。
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
if ([[SARAM RAM] selectedProjektIndex] == indexPath.row) [[SARAM RAM] setSelectedProjektIndex:0];
NSBlockOperation *start = [NSBlockOperation blockOperationWithBlock:^{
[[SAAufmassProject popFromDatabaseForGUID:[SARAM projektPool][indexPath.row]] deleteObjectAndAllDependencies];
[[self projectData] removeObjectAtIndex:indexPath.row];
}];
NSBlockOperation *refresh = [NSBlockOperation blockOperationWithBlock:^{
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
[self dataHasBeenDeleted];
}];
[refresh addDependency:start];
[[NSOperationQueue currentQueue] addOperation:start];
[[NSOperationQueue currentQueue] addOperation:refresh];
}
}
这段代码很好奇。它创建两个同步操作,使一个依赖于另一个。然后它继续将这些操作添加到当前队列(主队列!)。这有点低效并且无法实现任何性能优势。更糟糕的是,看起来有人有野心通过采用异步模式使这段代码响应更快,但并没有完全实现这个目标。 (这可能表明存在一些更深层次的体系结构问题使这变得困难。)
撇开这一点,您可能想要的是在更新模型对象和主线程中的 UI 时触发数据库的异步更新:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
if ([[SARAM RAM] selectedProjektIndex] == indexPath.row) [[SARAM RAM] setSelectedProjektIndex:0];
// get reference to the guid
NSString *guid = [SARAM projektPool][indexPath.row]];
// perform the deletion in some background queue
[self.databaseQueue addOperationWithBlock:^{
[[SAAufmassProject popFromDatabaseForGUID:guid] deleteObjectAndAllDependencies];
}];
// meanwhile, back on the ranch, we'll update the table view
[[self projectData] removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self dataHasBeenDeleted];
}
}
事实是,这提出了几个问题:
您的 SQLite 实现是否支持来自后台线程的更新?许多简单的实现都不能正确处理这个问题。
projektPool
使用与projectData
相同的索引,这让我很紧张。是deleteObjectAndAllDependencies
更新前者,而后者是在这个方法中更新。我怀疑这会是个问题。我想知道
popFromDatabaseForGUID
、deleteObjectAndAllDependencies
、projektPool
和projectData
之间存在更深层次的相互依赖关系。我还想知道这些是否真的是线程安全的(例如,当这些东西在后台运行时调用cellForRowAtIndexPath
时,模型和数据库是否处于一致状态)?
最重要的是,就我之前的观点而言,现有代码表明存在早期的并发处理尝试,我敢打赌,存在一些更深层次的架构问题阻碍了这一努力。问题是我们这里没有足够的东西来诊断更深层次的问题(我怀疑设计太复杂了,无法在这样的论坛中有效地传达)。
暂时假设 (a) 确实存在更深层次的架构问题; (b) 此代码的重构超出您的预期,您可能需要检查代码以查看是否有任何性能改进的战术机会。例如,如果 deleteObjectAndAllDependencies
正在执行大量单独的 SQL 语句来更新数据库,您是否使用事务来加快速度?使用 SQLite,会对性能产生巨大影响。
最重要的是,我可能会通过 "Instruments" 中的 "Time Profiler" 工具(包括 "Record Waiting Threads" 选项)来 运行 这段代码,并追踪性能的来源问题。看看是否有一些 SQL 相关的战术机会(例如交易、索引等)。