0

我有几个表视图,它们将JSON请求发送到服务器,将结果存储在核心数据中,并使用NSFetchedResultsController. 我正在试验 GCD,如下所示:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    // Perform JSON requests.
    dispatch_async(dispatch_get_main_queue(), ^{
        [theTableView reloadData];
    });
});

但是,这会导致 UI 中发生一些奇怪的事情。新的托管对象会呈现空白单元格,删除的托管对象会导致单元格重叠等。

但是,我发现如果我这样做,一切都会正确呈现。:

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [theTableView endUpdates];
    });
}

我想知道的是,为什么这是必要的?既然它是由于 触发的[theTableView reloadData],为什么它不自动包含在主队列中?我想可能是因为我没有明确地调用它。在那种情况下,我是否必须类似地包装我的所有功能?

4

2 回答 2

3

假设您从一个单独的线程中使用 main NSManagedObjectContext,这是不允许的。对于后台导入,您必须创建一个单独的托管对象上下文,在该上下文中导入对象,然后将更改保存/合并到主上下文。

一种可能性是使用主托管对象上下文的子上下文:

NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc]
                         initWithConcurrencyType:NSPrivateQueueConcurrencyType];
childContext.parentContext = mainManagedObjectContext;
[childContext performBlock:^{
    // Perform JSON requests.
    // Save objects to childContext.

    NSError *error;
    BOOL success = [childContext save:&error];
}];

“私有并发类型”的上下文创建自己的队列/线程,以便performBlock在后台执行(并且您需要/不得自己创建队列)。

保存childContext将更改合并到父级mainManagedObjectContext。这应该足以让获取的结果控制器获得更改通知并更新表视图。

有关托管对象上下文并发和嵌套上下文的更多信息,请参阅 OS X v10.7 和 iOS 5.0 的核心数据发行说明。

于 2013-10-09T12:26:08.790 回答
0

曾是

 [theTableView beginUpdates]

写在代码的任何地方?尝试删除它。我怀疑 UI 奇怪的事情正在发生,因为 beginUpdates 本身已经是异步的(不阻塞主线程),以便发生时髦的 UITableView 动画。

于 2013-10-09T12:05:26.230 回答