Coredata performFetch未获取新记录

时间:2016-12-14 09:57:24

标签: ios core-data swift3 nsfetchedresultscontroller

我在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)")
            }
        }
    })
}

我错过了什么吗?

1 个答案:

答案 0 :(得分:0)

从同一持久性存储中提取数据的两个或多个NSManagedObjectContext未自动注意到该存储中的更改。它们需要相互链接以接收在其中一个中执行的删除,插入和更新。可以使用以下两种方式之一建立这样的链接:

  1. 合并更改。
  2. 使用父/子模式。
  3. 合并更改通常是这样做的:

    // 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也有自己的特点,如thisthis

    最后,如果您必须使用大约几十万个对象导入相对较大的数据集,请在保存和导入数据时断开NSFetchedResultsController的连接。这将为您节省大量的主线程处理时间。这是计划:

    1. 处理数据时,请在保存背景背景之前发布自己的通知:

      [[NSNotificationCenter defaultCenter] postNotificationName:DBWillUpdateDataNotification object:self];
      
    2. 保存更改并将其合并到主上下文中,或将其推送到父上下文并保存。

    3. 发布另一条通知:

      [[NSNotificationCenter defaultCenter] postNotificationName:DBDidUpdateDataNotification object:self];
      
    4. 在视图控制器中观察这两个自定义通知。收到第一个时,请在delegate上将nil设置为NSFetchedResultsController。这将阻止他们在上下文中进行更改并报告它们。第二次接收时 - 再联系您的代表,请致电FRC上的-performFetch:并重新加载您的界面,即在表格视图上调用-reloadData,重新填充自定义标签等。