后台核心数据:使用单独的上下文和通知,但不使用新值更新数据库

Posted

技术标签:

【中文标题】后台核心数据:使用单独的上下文和通知,但不使用新值更新数据库【英文标题】:Core Data in background: Using separate context and notifications, but not updating DB with new values 【发布时间】:2013-10-10 16:37:56 【问题描述】:

概述:我有一个在后台运行的刷新过程(只使用 performInBackground 就可以了),其中一部分有数据库更新,所以我有一个单独的 MOC 用于后台线程。然后我使用 didSave 通知合并更改,但在 DB/我的 UI 中看不到这些更新。我在保存之前和之后记录了对象本身,我可以看到属性发生了变化,但是在通知调用的方法中,我在接收到的上下文中记录了对象并且它没有更新的值。我知道其他一些事情可能很丑陋,但只是想弄清楚这个核心数据。我以前只有一个 MOC 并且工作正常(非核心数据应该没问题),但我现在重新设计了一些东西以在后台运行,并希望使用单独的 MOC 的指导。

创建上下文、设置通知、设置属性并保存。保存后,值为0

// this creates context with same PSC as main MOC
  NSManagedObjectContext *context = [[MyAppDelegate application] temporaryContext];

[[NSNotificationCenter defaultCenter] addObserver:(MyAppDelegate *)[[UIApplication sharedApplication] delegate]
                                         selector:@selector(managedObjectContextDidSave:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:context];                  
NSLog(@"value is %d", [[myObject email] boolValue]); //value is 1
[myObject setEmail:[NSNumber numberWithBool:![[myObject email] boolValue]]]; 
NSError *error;     
if (![context save:&error]) 
    NSLog(@"Error in saving BriefCase object - error:%@" ,error);       
 
NSLog(@"value is %d", [[myObject email] boolValue]); //value is 0 now

在这里,我检查了我发送的 MOC,我看到所有值都是 1。所以当合并发生时,没有更新。如果我看到对象在保存后为 0,断开连接在哪里?

// Called when a ManagedObjectContext performs save operation
- (void)managedObjectContextDidSave:(NSNotification *)notification 
    NSManagedObjectContext *receivedMOC = [notification object];
    NSArray *items = [MyObjectClass getAllMyObjectsInManagedObjectContext:receivedMOC];
for (int i=0; i < [items count]; i++) 
    NSLog(@"value is %d", [[[items objectAtIndex:i] email] boolValue]);

添加上下文创建代码,可能是问题

- (NSManagedObjectContext *)temporaryContext 

NSManagedObjectContext *newContext = [[[NSManagedObjectContext alloc] init] autorelease];
NSPersistentStoreCoordinator *psc = [self.managedObjectContext persistentStoreCoordinator];
[newContext setUndoManager:nil];
[newContext setPersistentStoreCoordinator:psc];
return newContext;

【问题讨论】:

1) 我在您的代码中看不到实际的合并。 - 2) myObject 来自哪里? 非常感谢 mcuh 的回复!是的,抱歉我在此之后进行了合并,但我确信从通知收到的上下文没有更改。合并工作正常,但它没有合并更改导致上下文没有它们。 myObject 是在哪里创建的? 嗨,对不起,错过了这部分,myObject 被传递到方法中。也许这就是问题,因为它与另一个上下文相关联?生病调查它 myObject 与哪个上下文相关联?背景 MOC、主 MOC 还是第三个 MOC? 【参考方案1】:

temporaryContext 在每次调用时都会创建一个新的 MOC,因此您似乎实际上使用了 2 个不同的背景 MOC。 myModel 是在不同于

的 MOC 上创建的
NSManagedObjectContext *context = [[MyAppDelegate application] temporaryContext];

因此保存后者对myModel中的更改没有影响。

您必须修改您的代码,以便只创建和传递一个临时上下文。

【讨论】:

再次感谢,只是想跟进并说它现在工作!但我时不时地看到一些锁。当我查看锁之前调用的方法时,它访问了主 MOC。我的刷新过程中没有任何东西可以访问它,所有东西都可以访问后台 MOC。但是,我在想我对后台 MOC 所做的更改确实会使用 didSave 通知合并到主 MOC。如果我在执行 mergeChangesFromContextDidSaveNotification 时尝试查询一个 MOC,那会是问题吗?或者它是为了处理这个问题而设计的?【参考方案2】:

我没看到你在打电话

[mainMOC mergeChangesFromContextDidSaveNotification:saveNotification];

在处理通知时。这可以解释正在发生的事情。这应该在主线程上调用。

【讨论】:

我认为必须在主上下文中调用 mergeChangesFromContextDidSaveNotification。 @MartinR:谢谢,我就是这个意思;但我试图自定义太多答案而没有考虑太多...... 非常感谢 mcuh 的回复 sergio,抱歉所有问题!在此之后我进行了合并,但我确信从通知中收到的上下文没有更改。合并工作正常,但它没有合并更改导致上下文没有它们。 虽然你提出了一个关于线程的好观点,但合并调用是否总是发生在 main 上?因为我在后台更新那些东西,把主线程留给 UI。由于通知发布在线程 thyre 上,那么这个合并是否会在后台线程上并且是一个问题?这能解释为什么它收到的上下文没有变化吗?这就是最让我困惑的地方 我能做的唯一假设是myObject 不属于您的临时上下文...我还担心performSelectorInBackground 每次都会产生一个新线程-不确定是否是好的...您可能希望每次都创建一个新的临时上下文,或者通过 GCD 管理您的后台处理...

以上是关于后台核心数据:使用单独的上下文和通知,但不使用新值更新数据库的主要内容,如果未能解决你的问题,请参考以下文章

带有背景上下文的核心数据通知

NSFetchRequest 不读取更新的行 [关闭]

核心数据锁因为合并?

Core Data 3 托管对象上下文

在后台线程中将数据同步到服务器:核心数据中的多个上下文

核心数据:更新子上下文