为啥我的核心数据没有更新?

Posted

技术标签:

【中文标题】为啥我的核心数据没有更新?【英文标题】:Why is my core data not updating?为什么我的核心数据没有更新? 【发布时间】:2013-07-15 10:58:41 【问题描述】:

我在后台线程中更新核心数据,如下所示:

entry.message = [self contentForNoteWithEDML:note.content];
entry.dataLastModified = [NSDate date];
[entry.managedObjectContext save:nil];

dispatch_async(dispatch_get_main_queue(), ^
    NSError *error;

    if (![[self fetchedResultsController] performFetch:&error]) 
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    

    [self.tableView reloadData];
);

在表格视图的每个单元格上,它显示与fetchedResultsController 不同的条目。在主线程上,我在cellForRowAtIndexPath 中的dataLastModified 日期执行NSLog,并且日期不会更改为最新值。如果我关闭应用程序并再次运行它,它会更新单元格的内容并将dataLastModified 日期更改为正确的值。

它似乎正在根据需要更改数据,但我的tableview 在重新启动应用程序之前看不到更改。任何想法为什么?

编辑:在后台线程上执行 cellForRowAtIndexPath 中的 NSLog 会提供正确的数据,但在主线程上执行不会。

编辑 2:我的背景上下文如何工作:

NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];

[notificationCenter
    addObserver:[AppDelegate applicationDelegate].coreDataManager
    selector:@selector(mergeChanges:)
    name:NSManagedObjectContextDidSaveNotification
    object:[AppDelegate applicationDelegate].coreDataManager.managedObjectContext];
NSPersistentStoreCoordinator *journalDataPSC = [AppDelegate applicationDelegate].coreDataManager.managedObjectContext.persistentStoreCoordinator;

dispatch_queue_t addOrUpdateEntriesQueue = dispatch_queue_create("com.App.AddOrUpdateEntries", NULL);
dispatch_async(addOrUpdateEntriesQueue, ^

    NSManagedObjectContext *journalDataMOC = [[NSManagedObjectContext alloc] init];
    [journalDataMOC setPersistentStoreCoordinator:journalDataPSC];

    //Some code to get me an entry on this context
    entry.message = [self contentForNoteWithEDML:note.content];
    entry.dataLastModified = [NSDate date];
    [entry.managedObjectContext save:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:[AppDelegate applicationDelegate].coreDataManager];
    dispatch_async(dispatch_get_main_queue(), ^
        NSError *error;

        if (![[self fetchedResultsController] performFetch:&error]) 
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        

        [self.tableView reloadData];
    );
);
dispatch_release(addOrUpdateEntriesQueue);

【问题讨论】:

您是为后台线程使用子上下文还是手动创建的上下文?看起来更改没有传递到主上下文。 我正在使用手动创建的上下文。我将发布更多有关其工作原理的代码。 【参考方案1】:

确保您正确使用 MOC,它们不是线程安全的,只能在创建它们的线程中使用。在这种情况下,如果您使用正确,enter.managedObjectContext 与 MOC 不同获取的结果控制器(在主线程中)。

这意味着后台保存不一定会传播到主线程 MOC。在创建获取的结果控制器时添加观察者,确保在主线程中处理 NSManagedObjectContextDidSaveNotification

查看您的代码,我注意到以下几点:

您应该注册由后台 MOC 而不是主线程 MOC 抛出的保存通知。 您应该使用initWithConcurrencyType: 使用NSPrivateQueueConcurrencyType 初始化您的后台MOC 使用 NSPrivateQueueConcurrencyType 后,最好使用 performBlock: 进行更改并保存,而不是使用低级 GCD 调度方法。

【讨论】:

我发布了更多代码,你能看看并确保我这样做正确吗?【参考方案2】:

即使我对您的 coreDataManager 对象一无所知,您的通知注册也是错误的。您要观察的对象是您的后台托管对象上下文journalDataMOC,而不是您的coreDataManager

所以这应该可行,但请注意,您必须将注册移动到您的addOrUpdateEntriesQueue

[notificationCenter
    addObserver:[AppDelegate applicationDelegate].coreDataManager
    selector:@selector(mergeChanges:)
    name:NSManagedObjectContextDidSaveNotification
    object:journalDataMOC];

但总而言之,您应该使用 CoreData API 来完成这项工作(就像 Engin 所说的那样),因为它更干净。所以删除所有 GCD 和通知的东西并使用这个 sn-p(未测试):

NSManagedObjectContext *mainContext = [[[AppDelegate applicationDelegate] coreDataManager] managedObjectContext];
NSManagedObjectContext *journalDataMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[journalDataMOC setParentContext:mainContext];

[journaDataMOC performBlock:^

    //Some code to get me an entry on this context
    entry.message = [self contentForNoteWithEDML:note.content];
    entry.dataLastModified = [NSDate date];

    [journalDataMOC save:nil];

    [NSOperationQueue mainQueue] addOperationWithBlock:^

        NSError *error;
        [mainContext save:&error];

        if (![[self fetchedResultsController] performFetch:&error]) 
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        

        [self.tableView reloadData];    
    ];
];

journalDataMOC 保存时,它会将更改“推送”到括号上下文(mainContext)。

请注意,您的[[[AppDelegate applicationDelegate] coreDataManager] managedObjectContext] 必须使用NSMainQueueConcurrencyType 类型进行初始化。另请注意,您必须在此处或将来的某个时间保存您的 mainContext,以将您的更改持久保存到数据库中。

【讨论】:

以上是关于为啥我的核心数据没有更新?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 EF 核心忽略我对数据集的更新?

核心数据 - 为啥我的 NSPredicate 没有产生正确的 SQL 查询?

为啥我的“数据”。“数据”没有使用 ChangeNotifierProvider 在 ChangeNotifier 类中更新?

为啥更新操作没有发布任何数据?

为啥我的 Apollo 缓存更新没有反映在我的查询中?

为啥我的组件基于 redux 的 props 没有更新?