我在iOS10(Swift3)应用程序中集成了coredata框架,从服务器和显示器中提取数据。当应用程序首次启动时,核心数据不会有任何记录。与服务器交换一些信息后,它开始在后台线程中同步。我能够看到通过Web服务从服务器下载数据,解析并存储在核心数据中。但是,如果我退出并启动应用程序,它会显示所有记录。
在我的视图控制器中,我使用" NSFetchedResultsController"在" TableView"中显示记录。我正在创建获取结果控制器,如下所示:
fileprivate lazy var inspirationsResults: NSFetchedResultsController<Inspiration> = {
// Create Fetch Request
let fetchRequest: NSFetchRequest<Inspiration> = Inspiration.fetchRequest()
// Configure Fetch Request
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timeStamp", ascending: false)]
// Create Fetched Results Controller
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataManager.shared.getContext(), sectionNameKeyPath: nil, cacheName: nil)
// Configure Fetched Results Controller
fetchedResultsController.delegate = self
return fetchedResultsController
}()
在viewDidLoad方法中,我写了下面的代码来获取:
do {
try self.inspirationsResults.performFetch()
} catch {
let fetchError = error as NSError
print("\(fetchError), \(fetchError.userInfo)")
}
我还添加了委托方法&#34; controllerWillChangeContent,controllerDidChangeContent&amp; didChangeObject&#34;处理更新/修改。
我使用persistentContainer来保存对象:
func addInspirations(_ inspirations:[[String: AnyObject]]) {
persistentContainer.performBackgroundTask({ (bgContext) in
bgContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
for tInspiration in inspirations {
let inspiration = Inspiration(context: bgContext)
inspiration.inspirationID = tInspiration[kInspirationId] as! Int32
inspiration.inspirationName = tInspiration[kInspirationName] as? String
}
if bgContext.hasChanges {
do {
try bgContext.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
})
}
我错过了什么吗?
答案 0 :(得分:0)
从同一持久性存储中提取数据的两个或多个NSManagedObjectContext
未自动注意到该存储中的更改。它们需要相互链接以接收在其中一个中执行的删除,插入和更新。可以使用以下两种方式之一建立这样的链接:
合并更改通常是这样做的:
// initializing your contexts
self.mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
self.mainContext.persistentStoreCoordinator = self.coordinator;
self.backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.backgroundContext.persistentStoreCoordinator = self.coordinator;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mainContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:self.mainContext];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:self.backgroundContext];
稍后某处:
- (void)mainContextDidSave:(NSNotification *)notification
{
[self.backgroundContext performBlock:^{
[self.backgroundContext mergeChangesFromContextDidSaveNotification:notification];
}];
}
- (void)backgroundContextDidSave:(NSNotification *)notification
{
[self.mainContext performBlock:^{
[self.mainContext mergeChangesFromContextDidSaveNotification:notification];
}];
}
这可确保您的上下文在持续更改后立即收到更改。
可能的父/子设置变体之一是:
// when initializing your contexts
self.mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
self.mainContext.persistentStoreCoordinator = self.coordinator;
self.backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.backgroundContext.parentContext = self.mainContext;
// when saving your background changes
[self.backgroundContext performBlock:^{
__block NSError *error;
if ([self.backgroundContext save:&error) {
[self.mainContext performBlock:^{
if (![self.mainContext save:&error]) {
NSLog(@"Error saving main context");
}
}];
} else {
NSLog(@"Error saving background context");
}
}];
这会将更改从后台上下文推送到主上下文,并将它们保存在持久存储中。
此外,NSFetchedResultsController
也有自己的特点,如this或this。
最后,如果您必须使用大约几十万个对象导入相对较大的数据集,请在保存和导入数据时断开NSFetchedResultsController
的连接。这将为您节省大量的主线程处理时间。这是计划:
处理数据时,请在保存背景背景之前发布自己的通知:
[[NSNotificationCenter defaultCenter] postNotificationName:DBWillUpdateDataNotification object:self];
保存更改并将其合并到主上下文中,或将其推送到父上下文并保存。
发布另一条通知:
[[NSNotificationCenter defaultCenter] postNotificationName:DBDidUpdateDataNotification object:self];
在视图控制器中观察这两个自定义通知。收到第一个时,请在delegate
上将nil
设置为NSFetchedResultsController
。这将阻止他们在上下文中进行更改并报告它们。第二次接收时 - 再联系您的代表,请致电FRC上的-performFetch:
并重新加载您的界面,即在表格视图上调用-reloadData
,重新填充自定义标签等。