Ios Coredata performFetch未获取新记录
我在iOS10(Swift3)应用程序中集成了coredata框架,该应用程序从服务器和显示器中提取数据。当应用程序第一次启动时,核心数据没有任何记录。在与服务器交换一些信息后,它开始在后台线程中同步。我能够看到数据通过web服务从服务器下载,解析并存储在核心数据中。但如果我退出并启动应用程序,它会显示所有记录 在我的视图控制器中,我使用“NSFetchedResultsController”在“TableView”中显示记录。我正在创建获取结果控制器,如下所示:Ios Coredata performFetch未获取新记录,ios,core-data,swift3,nsfetchedresultscontroller,Ios,Core Data,Swift3,Nsfetchedresultscontroller,我在iOS10(Swift3)应用程序中集成了coredata框架,该应用程序从服务器和显示器中提取数据。当应用程序第一次启动时,核心数据没有任何记录。在与服务器交换一些信息后,它开始在后台线程中同步。我能够看到数据通过web服务从服务器下载,解析并存储在核心数据中。但如果我退出并启动应用程序,它会显示所有记录 在我的视图控制器中,我使用“NSFetchedResultsController”在“TableView”中显示记录。我正在创建获取结果控制器,如下所示: fileprivate laz
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
}()
我还添加了委托方法“controllerWillChangeContent、controllerDidChangeContent和didChangeObject”来处理更新/修改
我正在使用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)")
}
}
})
}
我遗漏了什么吗?从同一个持久存储中提取数据的两个或多个
NSManagedObjectContext
s没有自动注意到该存储中的更改。它们需要相互链接以接收其中一个中执行的删除、插入和更新。可通过以下两种方式之一建立此类链接:
// 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
也有自己的特性,比如or
最后,如果必须导入包含大约几十个数千个对象的相对较大的数据集,请在保存和导入数据时断开NSFetchedResultsController
s。这将为您节省大量的主线程处理时间。计划如下:
[[NSNotificationCenter defaultCenter] postNotificationName:DBWillUpdateDataNotification object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:DBDidUpdateDataNotification object:self];
NSFetchedResultsController
s上将代理设置为nil
。这将阻止他们在上下文中寻找变化并报告它们。当收到第二个请求时-将您的代表连接回,在FRC上调用-performFetch:
,并重新加载界面,即在表视图上调用-reloadData
,重新填充自定义标签等
从同一个持久存储中提取数据的两个或多个
NSManagedObjectContext
s不会自动注意到该存储中的更改。它们需要相互链接以接收其中一个中执行的删除、插入和更新。可通过以下两种方式之一建立此类链接:
// 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
也有自己的特性,比如or
最后,如果必须导入包含大约几十个数千个对象的相对较大的数据集,请在保存和导入数据时断开NSFetchedResultsController
s。这将为您节省大量的主线程处理时间。计划如下:
[[NSNotificationCenter defaultCenter] postNotificationName:DBWillUpdateDataNotification object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:DBDidUpdateDataNotification object:self];
NSFetchedResultsController
s上将代理设置为nil
。这将阻止他们在上下文中寻找变化并报告它们。当收到第二个请求时-将您的代表连接回,在FRC上调用-performFetch:
,并重新加载界面,即在表视图上调用-reloadData
,重新填充自定义标签等
您的后台和主线程上下文是否与
mergeChangesFromContextDidSaveNotification:
连接?还是父子连接?@bteapot,我用“保存”详细信息更新了代码。因为我已经将后台任务的mergePolicy设置为NSMergeByPropertyObjectTrumpMergePolicymergePolicy
在导致问题的原因中没有任何作用。我会写一个答案。是的,你是对的。合并策略只是为了在保存时解决冲突。因此@bteapot的问题仍然是:这两个上下文(bgContext
和CoreDataManager.shared.getContext()
)是如何关联的?显示每个线程的初始化。您的后台和主线程上下文是否与合并更改从ContextDidSaveNotification:
连接?还是父子连接?@bteapot,我用“保存”详细信息更新了代码。因为我已经将后台任务的mergePolicy设置为NSMergeByPropertyObjectTrumpMergePolicymergePolicy
在导致问题的原因中没有任何作用。我会写一个答案。是的,你是对的。合并策略只是为了在保存时解决冲突。因此@bteapot的问题仍然是:这两个上下文(bgContext
和CoreDataManager.shared.getContext()
)是如何关联的?显示