【问题标题】:NSOperationQueue blocks UITableViewNSOperationQueue 阻塞 UITableView
【发布时间】:2015-04-24 22:18:56
【问题描述】:

以下代码由我公司的另一位员工编写,但我现在必须解决性能问题...

deleteObjectAndAllDependencies 方法从我们的 SQLite DB 中删除项目和相关数据...

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

【问题讨论】:

    标签: ios objective-c sqlite uitableview nsoperationqueue


    【解决方案1】:

    这段代码很奇怪。它创建了两个同步操作,使一个依赖于另一个。然后它继续将这些操作添加到当前队列(主队列!)。这有点低效,并且无法实现任何性能优势。更糟糕的是,看起来有人有野心通过采用异步模式使这段代码更具响应性,但并没有完全实现这个目标。 (这可能表明存在一些更深层次的架构问题使这变得困难。)

    除此之外,您可能想要的是在更新模型对象和主线程中的 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更新了前者,而后者是在这个方法中更新的。我怀疑这会是个问题。

    • 我想知道popFromDatabaseForGUIDdeleteObjectAndAllDependenciesprojektPoolprojectData 之间存在哪些更深层次的相互依赖关系。我还想知道这些是否真的是线程安全的(例如,当这些东西在后台进行时调用cellForRowAtIndexPath,模型和数据库是否处于一致状态)?

    归根结底,就我之前的观点而言,现有代码表明有早期的并发处理尝试,我敢打赌,有一些更深层次的体系结构问题阻碍了这一努力。问题是我们这里没有足够的数据来诊断更深层次的问题(而且我怀疑设计过于复杂,无法在这样的论坛中有效地传达这一点)。

    假设 (a) 确实存在更深层次的架构问题; (b) 该代码的重构超出了您的预期,您可能需要查看代码以查看是否有任何提高性能的战术机会。例如,如果deleteObjectAndAllDependencies 正在执行大量单独的 SQL 语句来更新数据库,那么您是否使用事务来加快速度?使用 SQLite,可能会对性能产生巨大影响。

    最后,我可能会通过“Instruments”中的“Time Profiler”工具(包括“Record Waiting Threads”选项)运行此代码,并追踪性能问题的根源。看看是否可能存在一些与 SQL 相关的战术机会(例如,事务、索引等)。

    【讨论】:

    • 感谢您的长篇回答。我明天回到办公室时会回复。
    • 感谢您的详细重播。我决定将此性能问题推到下一次软件更新,以便有时间有效地审查和重构它......
    猜你喜欢
    • 2013-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多