替换多线程核心数据中的数据

时间:2014-04-08 08:12:10

标签: ios objective-c multithreading uitableview core-data

我正在使用Marcus Zarra在他的书中介绍的三级多线程核心数据。 tempMOC用于处理困难的任务,mainMOC用于UI管理,writerMOC用于将数据写入持久性存储。

我正在尝试将此模型与我的UITableView集成 每次用户 pull-to-refresh 我都会处理下载,解析和加载此数据。在此过程中还有一个额外步骤 - 删除权利的previos条目。我希望这是顺利的,因此,当前UITableView(MOC)将等到最后一刻被清理,因此删除和加载新数据之间的这个差距将不会持续约4秒。

这是我的方法,每当我 pull-to-refresh 时调用(我已经删除了解析以保持代码更清晰):

- (void)loadTimetableToCoreData:(id)timetable
{
    [self.pullToRefresh finishLoading];

    // Initializing temporary context
    NSManagedObjectContext *tempContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    tempContext.parentContext = self.moc;

    [tempContext performBlock:^{
        // Parsing JSON data
    }];

    [self deleteAllObjects:@"Timetable"];
    NSLog(@"Finished loading to temp MOC");

    [tempContext performBlock:^{
        // Saving procedure with multithreading
        NSError *error;
        if (![tempContext save:&error]) {
            NSLog(@"Couldn't save: %@", [error localizedDescription]);
        }
        NSLog(@"Finished saving to temp MOC");

        [self.moc performBlock:^{
            // Save groups to presistant store
            NSError *error;
            if (![self.moc save:&error]) {
                NSLog(@"Couldn't save: %@", [error localizedDescription]);
            }
            NSLog(@"Finished saving to main MOC");

            [self.writer performBlock:^{
                // Save groups to presistant store
                NSError *error;
                if (![self.writer save:&error]) {
                    NSLog(@"Couldn't save: %@", [error localizedDescription]);
                }
                NSLog(@"Finished saving to writer MOC");
            }];
        }];
    }];
}

我还放了一些日志,如果你运行这段代码就像:

2014-04-08 09:55:28.349 devPlan[21125:1803] Finished loading to temp MOC
2014-04-08 09:55:33.145 devPlan[21125:1803] Finished saving to temp MOC
2014-04-08 09:55:33.650 devPlan[21125:60b] Finished saving to main MOC
2014-04-08 09:55:33.652 devPlan[21125:60b] Finished saving to writer MOC

因此,您可以看到加载和保存到临时MOC之间存在这种差距。这很好,因为有很多工作正在进行,但我想等待[self deleteAllObjects:@"Timetable"];,直到这项工作完成。执行此操作时,它将擦除所有数据,当它再次被真实加载时,它会显示在UITableView中 - 但仍然存在UITableView为空的时间间隔...

我应该怎么做才能解决问题?以下是我到目前为止所做的尝试清单:

  • 将此删除方法放在下载方法的各个位置。
  • 与MOC performBlock:performBlockAndWait:混淆。
  • 使用deleteMOC获取并初始化NSFetchRequest,等待处理数据,然后调用删除方法。

我必须告诉你,我坚持这个......而且这让我很困扰,但我认为必须对此有合理的解释!

修改

以下是负责删除的方法的代码:

- (void)deleteAllObjects:(NSString *)entityDescription
{
    // Initializing temporary context
    NSManagedObjectContext *tempContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    tempContext.parentContext = self.moc;

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityDescription inManagedObjectContext:tempContext];
    [fetchRequest setEntity:entity];

    NSError *error;
    NSArray *items = [tempContext executeFetchRequest:fetchRequest error:&error];

    [tempContext performBlockAndWait:^{
        for (NSManagedObject *managedObject in items) {
            [tempContext deleteObject:managedObject];
        }

        NSError *error;
        if (![tempContext save:&error]) {
            NSLog(@"Error deleting %@ - error:%@", entityDescription, [error localizedDescription]);
        }
    }];
}

2 个答案:

答案 0 :(得分:4)

首先是简单的答案;我会在保存-deleteAllObjects之后放置tempContext

但我会质疑从表中删除所有内容的想法。你能不能只删除需要删除的对象,添加需要添加的对象并更新需要更新的对象?通过从NSManagedObjectContextDidSaveNotification捕获通知,您可以解析该数据并更清晰地呈现(imho)数据。

更新

我不关心它的解析(插入,更新,删除)部分,因为谁在乎它需要多长时间。无论如何,这都是人类可感知的,所以我们不会在那里做魔术。我正在考虑更多的桌面视图的用户体验消失,然后重新出现,而不是单个单元格更新和求助自己。我个人认为这是一种更清洁,更光滑的体验。

加倍听起来就像NSFetchedResultsController委托方法或-deleteAllObjects中存在某些不稳定因素。小心发帖吗?

更新

好的,所以你实际上删除了该表中的所有内容。是否有理由删除与合并?

现在我了解了一点,我会做这个事件顺序:

  1. 处理数据
  2. 使用UITableView
  3. 阻止-beginUpdates更新
  4. 删除所有数据
  5. 保存两个上下文
  6. 使用UITableView
  7. 取消屏蔽-endUpdates

    那应该给你一个更多"瞬间"刷新tableview。

    我不喜欢处理数据的删除/插入方式,但在您的情况下可能是合适的。

答案 1 :(得分:0)

在我的旧代码的帮助下,我已经发现了这个:

NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:@"Timetable"];
[r setIncludesPendingChanges:NO];
NSArray *existingTimetables = [tempContext executeFetchRequest:r error:nil];

for (Timetable *table in existingTimetables) {
    [tempContext deleteObject:table];
}

因此,我正在提取时间表,而不是将其与tempContext内的待定更改混淆。有了这个代码,一切都像它应该的工作,但阻止主线程!但我想这有资格成为另一个问题。