NSFetchedResultsController 一致延迟更新 UITableView 单元格;插入立即起作用
NSFetchedResultsController consistent delay in updating UITableView cell; insert works instantaneously
我有一个 UITableView
(带有自定义单元格,如果重要的话)连接到一个 NSFetchedResultsController
。我的应用程序还使用推送通知。当远程通知到达时,我分两个阶段更新我的(核心)数据模型:
1) 获取标题(带有一些自定义数据)并将其存储为新的核心数据Entity
。这里我调用NSManagedObjectContext save()
。 NSFetchedResultsController
获取插入并使用 NSFetchedResultsChangeType
=NSFetchedResultsChangeInsert
触发它的委托方法 didChangeObject
。 tableview 立即更新。 (插入新行)
2) 通过NSURLSession
下载更多与单元格相关的内容,将其插入上面的Entity
,然后再次调用save() method
。 NSFetchedResultsController
再次获取更新并使用 NSFetchedResultsChangeType
=NSFetchedResultsChangeUpdate
触发它的委托方法 didChangeObject
。这是我调用 configureCell
方法的地方。 tableView 已更新,但持续延迟约 10 秒。
在这两个阶段(download-context save-update tableview)需要显示的数据已经被核心数据持久化了。 (例如,在我的 configureCell..
方法中,我知道我没有将任何单元格标签设置为 nil
或类似的。
我的 NSFetchedResultsController
委托方法:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.mainTableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.mainTableView endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.mainTableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:(MessageTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
}
}
我在里面尝试过的其他东西case NSFetchedResultsChangeUpdate:
- 尝试在上下文
save
之前调用 processPendingChanges
- 调用了
reloadRowsAtIndexPaths
而不是直接调用configureCell
- 尝试将 update.. 方法包装在
beginUpdates
和 endUpdates
中(即使我已经有一对可以完成这项工作)
[tableView reloadData]
numberOfRowsInSection
不为0!
- 仅在主线程上
NSFetchedResultsController
委托方法 运行。
简而言之,所有(?)正确的委托方法都被正确调用。然而,我在更新单元格时看到一致的 ~10 秒延迟。然而,插入几乎是瞬间发生的。有任何想法吗?
@Paulw11 关于 dispatch_async...
的评论让我朝着正确的方向前进。问题在于我一直在两个不同的线程中使用同一个 ManagedObjectContext
对象,即使它们不会同时访问它。一旦我在主队列上(通过将其包装在 dispatch_async(dispatch_get_main_queue,^{ UIUpdate code here });
中)调度我的 save
调用(在后台线程上),延迟就消失了。一种可能的解释是,在后台线程上调用 save
会导致在后台线程上调用委托方法。
无论如何,回到解决方案 - 永远不要在多个线程之间共享相同的 ManagedObjectContext
对象。 Use parent/child context relationships 如果您在多个线程中更新核心日期。 NSFetchedResultsController
也很适合这种模式。
我有一个 UITableView
(带有自定义单元格,如果重要的话)连接到一个 NSFetchedResultsController
。我的应用程序还使用推送通知。当远程通知到达时,我分两个阶段更新我的(核心)数据模型:
1) 获取标题(带有一些自定义数据)并将其存储为新的核心数据Entity
。这里我调用NSManagedObjectContext save()
。 NSFetchedResultsController
获取插入并使用 NSFetchedResultsChangeType
=NSFetchedResultsChangeInsert
触发它的委托方法 didChangeObject
。 tableview 立即更新。 (插入新行)
2) 通过NSURLSession
下载更多与单元格相关的内容,将其插入上面的Entity
,然后再次调用save() method
。 NSFetchedResultsController
再次获取更新并使用 NSFetchedResultsChangeType
=NSFetchedResultsChangeUpdate
触发它的委托方法 didChangeObject
。这是我调用 configureCell
方法的地方。 tableView 已更新,但持续延迟约 10 秒。
在这两个阶段(download-context save-update tableview)需要显示的数据已经被核心数据持久化了。 (例如,在我的 configureCell..
方法中,我知道我没有将任何单元格标签设置为 nil
或类似的。
我的 NSFetchedResultsController
委托方法:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.mainTableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.mainTableView endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.mainTableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:(MessageTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
}
}
我在里面尝试过的其他东西case NSFetchedResultsChangeUpdate:
- 尝试在上下文
save
之前调用 - 调用了
reloadRowsAtIndexPaths
而不是直接调用configureCell
- 尝试将 update.. 方法包装在
beginUpdates
和endUpdates
中(即使我已经有一对可以完成这项工作) [tableView reloadData]
numberOfRowsInSection
不为0!- 仅在主线程上
NSFetchedResultsController
委托方法 运行。
processPendingChanges
简而言之,所有(?)正确的委托方法都被正确调用。然而,我在更新单元格时看到一致的 ~10 秒延迟。然而,插入几乎是瞬间发生的。有任何想法吗?
@Paulw11 关于 dispatch_async...
的评论让我朝着正确的方向前进。问题在于我一直在两个不同的线程中使用同一个 ManagedObjectContext
对象,即使它们不会同时访问它。一旦我在主队列上(通过将其包装在 dispatch_async(dispatch_get_main_queue,^{ UIUpdate code here });
中)调度我的 save
调用(在后台线程上),延迟就消失了。一种可能的解释是,在后台线程上调用 save
会导致在后台线程上调用委托方法。
无论如何,回到解决方案 - 永远不要在多个线程之间共享相同的 ManagedObjectContext
对象。 Use parent/child context relationships 如果您在多个线程中更新核心日期。 NSFetchedResultsController
也很适合这种模式。