我正在使用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
为空的时间间隔...
我应该怎么做才能解决问题?以下是我到目前为止所做的尝试清单:
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]);
}
}];
}
答案 0 :(得分:4)
首先是简单的答案;我会在保存-deleteAllObjects
之后放置tempContext
。
但我会质疑从表中删除所有内容的想法。你能不能只删除需要删除的对象,添加需要添加的对象并更新需要更新的对象?通过从NSManagedObjectContextDidSaveNotification
捕获通知,您可以解析该数据并更清晰地呈现(imho)数据。
我不关心它的解析(插入,更新,删除)部分,因为谁在乎它需要多长时间。无论如何,这都是人类可感知的,所以我们不会在那里做魔术。我正在考虑更多的桌面视图的用户体验消失,然后重新出现,而不是单个单元格更新和求助自己。我个人认为这是一种更清洁,更光滑的体验。
加倍听起来就像NSFetchedResultsController
委托方法或-deleteAllObjects
中存在某些不稳定因素。小心发帖吗?
好的,所以你实际上删除了该表中的所有内容。是否有理由删除与合并?
现在我了解了一点,我会做这个事件顺序:
UITableView
-beginUpdates
更新
UITableView
-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
内的待定更改混淆。有了这个代码,一切都像它应该的工作,但阻止主线程!但我想这有资格成为另一个问题。