【问题标题】:FetchedResultsController doesn't see the changes in managedObjectContext after data import数据导入后,FetchedResultsController 看不到 managedObjectContext 的变化
【发布时间】:2012-07-17 04:41:34
【问题描述】:

我正在处理我的应用程序中的数据导入部分,为了使 UI 更可靠,我关注了这篇 Marcus Zarra 文章 http://www.cimgf.com/2011/08/22/importing-and-displaying-large-data-sets-in-core-data/

这个想法是你在后台的单独上下文中进行导入(我为此使用 GCD),并且你的 fetchedResultsController 的上下文通过观察 NSManagedObjectContextDidSaveNotification 来合并更改。

我遇到的问题对我来说很奇怪——我的 fetchedResultsController 没有获得这些更改,并且在新数据到来时不会重新加载 TableView。 但是,如果我触发以下方法,该方法会进行获取并重新加载表 - 它会全部获取。

- (void)updateUI
{                                         
  NSError *error;
  if (![[self fetchedResultsController] performFetch:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
  }
  [self.tableView reloadData];
}

所以现在我在获得 NSManagedObjectContextDidSaveNotification 以使其工作时调用该方法,但它对我来说看起来很奇怪和讨厌。

 - (void)contextChanged:(NSNotification*)notification
{
  if ([notification object] == [self managedObjectContext]) return;

  if (![NSThread isMainThread]) {
    [self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:NO];
    return;
  }

  [[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
  //TODO:Make it work as it should - merge, without updateUI
   [self updateUI];//!!!Want to get rid of this!
}

为什么会这样? 这是负责解析数据并添加观察者的代码。

- (void)parseWordsFromServer:(NSNotification *)notification
{

  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) , ^{
    NSDictionary *listInJSON = [notification userInfo];
    wordsNumbers = [[listInJSON valueForKey:@"words"]mutableCopy];

    if ([wordsNumbers count])
    {
      [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:nil];

//新线程的新上下文 NSManagedObjectContext *backContext = [[AppDelegate sharedAppDelegate]backManagedObjectContext];

      //Get all the words we already have on this device
      NSArray *wordsWeHave = [Word wordsWithNumbers:wordsNumbers inManagedContext:backContext];
      //Add them to this list
      for (Word *word in wordsWeHave)
        [[List listWithID:[currentList listID] inManagedObjectContext:backContext]addWordsObject:word];
      [backContext save:nil];!//Save the context - get the notification
         }

  });

}

编辑 我使用NSFetchedResutsControllerDelegate,确实,如果我没有,我怎么能假装我的tableview被更新?

更新决定只是转移到父子范式

【问题讨论】:

    标签: objective-c ios core-data nsfetchedresultscontroller nsmanagedobjectcontext


    【解决方案1】:

    这个问题已经讨论过很多次了,比如NSFetchedResultsController doesn't show updates from a different context,很难理解是怎么回事,但我没有什么笔记。

    首先,您违反了一条简单规则:每个线程都需要一个托管对象上下文 (Concurrency with Core Data Section)。

    为每个线程创建一个单独的托管对象上下文并共享一个 单个持久存储协调器。

    因此,在您的自定义线程中访问主上下文,获取其持久协调器并将其设置为新上下文。

    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
    [moc setPersistentStoreCoordinator:persistentStoreCoordinatorGrabbedFromAppDelegate];
    

    第二,不需要注册

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:nil];
    

    在新线程中。只需在创建新线程的类中(或在应用程序委托中)注册它。

    最后,如果您不使用NSFetchedResutsControllerDelegate,请使用它。它允许摆脱重新加载数据表。当上下文发生变化时,委托会响应变化:编辑、删除、添加。

    从 iOS 5 开始,您可以使用新的 Core Data API 并使用新的confinement mechanism 让您的生活更轻松。

    编辑

    来自 @mros 评论。

    Multi-Context CoreData

    它可能会帮助您更多地了解 使用父子核心数据模型。我特别喜欢那个位 关于使用私有队列上下文来处理持久存储。 确保通读整篇文章,因为开头 显示如何不这样做。

    希望对您有所帮助。

    【讨论】:

    • 谢谢你的回答,但让我在这里澄清一下:1 - 我在新线程中创建了一个新的 ManagedObjectContext,这里是: NSManagedObjectContext *backContext = [[AppDelegate sharedAppDelegate]backManagedObjectContext]; 2-我在创建控制器时使用委托:self.fetchedResultsController = theFetchedResultsController; fetchedResultsController.delegate = self; 3-添加观察者的地方有什么区别?它不是线程安全的吗?
    • @NikitaPestrov 关于第一点,backManagedObjectContext 是什么?我看不到您在哪里创建上下文。然后,关于第三点,我真的建议在主线程中注册保存通知。再次阅读 Marcus Zarra 的帖子以清楚说明。干杯。
    • @NikitaPestrov 关于通知的说明。如您所见,回调通知对在后台线程中创建的上下文有效。当这些线程发出通知时,回调执行与主上下文的合并操作。通常,我在放置主上下文的地方注册保存通知(及其回调)。希望对您有所帮助。
    • 很好的答案,但这里有一个资源可以帮助您更多地了解使用父子核心数据模型的优势。我特别喜欢使用私有队列上下文来处理持久存储。确保通读整件事,因为开头显示了如何不这样做。 cocoanetics.com/2012/07/multi-context-coredata
    • @mros 谢谢!我会把它添加到我的答案中。
    猜你喜欢
    • 2021-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    • 1970-01-01
    • 2021-05-22
    • 1970-01-01
    • 2019-01-16
    相关资源
    最近更新 更多