NSOperationQueue阻止UITableView

时间:2015-02-23 14:47:34

标签: ios objective-c sqlite uitableview nsoperationqueue

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

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

1 个答案:

答案 0 :(得分: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,可能会对性能产生巨大影响。

最重要的是,我可以通过" Time Profiler"运行此代码。工具"仪器" (包括"记录等待线程"选项),并跟踪性能问题的来源。看看是否存在一些与SQL相关的战术机会(例如,交易,索引等)。