合并到父/主上下文后,子上下文对象变空

我正在使用核心数据的multithreading应用程序。 具有讽刺意味的是,当我得知Core Data不是线程安全的时候,我认为应用程序已经接近完成了…因此,我现在添加了多上下文,而不是从Xcode模板获得的单一上下文一直工作到目前为止,真的,但是这比我所猜测的技巧更有运气)

我试图使用与父/子上下文,这将适合我想要做的,但是当我在我的子上下文中插入有效的数据/属性的有效的对象的iOS 5.0的方法,他们都成为零,或0(取决于属性types)在父上下文中。

我注意到有类似的post,但没有任何答案。

家长MOC获取来自儿童MOC的空数据的变化

NSManagedObject值是正确的,然后在从父对象到子对象NSManagedObjectContext合并更改时不正确

这里有一些代码来获得这个想法。

我有一个单独的pipe理器,用户界面用来“做东西”,然后在任务完成时使用委托或callback。 那个经理又有一个模型pipe理者来处理持久的数据pipe理,还有一些其他的comm-managers跟web / REST-API等等。

- (void) doSomeStuff:(NSString*)someParam callbackObject:(NSObject*)object onSuccess:(SEL)successSelector onFailure:(SEL)failureSelector { //Kick as an async thread since we don't want to disturb the UI dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), ^(void) { //Ask model manager for a nice context to work with... //NOTE; All contexts (private ones) are stored in a NSDictionary using currentThread as key, so that we always can access the "correct" context at anytime if we need to insert/delete/change anything in the context NSManagedObjectContext* privateContext = [self.modelManager getManagedObjectContext]; //Perform stuff in block since our context is of NSPrivateQueueConcurrencyType [privateContext performBlockAndWait:^{ //... do the actual stuff, go online, talk to a REST-API, wait for things, which will eventually result in a new object being created User* user = ...; //Store object in model manger which is my abstraction of CoreData //NOTE: the modelManager will get a reference to the currently used privateContext and use it to insert the object [self.modelManager addUser:user]; //Save model! [self.modelManager save]; }]; //Trigger callback, if applicable if (loggedInUserGuid && successSelector) { [object performSelectorOnMainThread:successSelector withObject:loggedInUserGuid waitUntilDone:NO]; } }); } 

modelManager中的保存function考虑了上下文concurrencyType,并且在使用子/父上下文时将按照规范行事;

 - (void) save { //Get current context... NSManagedObjectContext* currentContext = [self getManagedObjectContext]; //If the current context has any changes... if ([currentContext hasChanges]) { //Changes detected! What kind of context is this? switch (currentContext.concurrencyType) { case NSPrivateQueueConcurrencyType: { NSError* error = nil; if (![currentContext save:&error]) abort(); if (self.mainManagedObjectContext hasChanges]) { [self.mainManagedObjectContext performBlockAndWait:^{ NSError *mainError; if (![self.mainManagedObjectContext save:&mainError]) abort(); }]; } break; } .... } } } 

通过在保存子上下文和父/上下文之前和之后添加debugging打印,我注意到插入的对象在子上下文中很好,子上下文说“hasChanges == YES”,而主上下文像预期的那样说“hasChanges == NO”。

 (entity: User; id: 0x10c06c8c0 <x-coredata:///User/tDFBBE194-44F9-44EC-B960-3E8E5374463318> ; data: { created = nil; emailAddress = "wilton@millfjord.se"; firstName = Wilton; guid = "2eaa77fa-0d2c-41b8-b965-c4dced6eb54a"; lastName = Millfjord; nbrOfOfflineKeys = 5; password = 123456; }) 

然后保存main-context,在保存之前查看它的registeredObjects,我们可以看到“hasChanges == YES”(预期在孩子将插入的对象保存/合并到父项之后),而且 – 所有参数和属性现在为零或0,取决于属性types…;

 (entity: User; id: 0x10c06c8c0 <x-coredata:///User/tDFBBE194-44F9-44EC-B960-3E8E5374463318> ; data: { created = nil; emailAddress = nil; firstName = nil; guid = nil; lastName = nil; nbrOfOfflineKeys = 0; password = nil; }) 

正如你所看到的,ID是相同的,所以它是“相同”的对象,但没有/重置内容。 我尝试了所有“setMergePolicy”的各种组合,但没有效果。

我甚至尝试过使用<iOS 5.0的方法添加一个NSNotificationCentre的方法,我“mergeChangesFromContextDidSaveNotification”,我唯一可以validation的是,在NSNotification参数中的数据是有效的,“好数据”,但主要上下文还没有正确更新。 结果仍然是一个空洞的对象。

期待您的想法和想法。

/马库斯

更新

创build新的托pipe对象时使用的代码,使用主要上下文,而不pipe当时正在运行哪个线程/上下文执行块…

 NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:self.mainManagedObjectContext]; User* user = (User *)[[User alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; 

之后对象用户挂起而没有上下文,直到后来我决定将其添加到托pipe上下文(使用getManagedObjectContext生成适当的/当前的上下文)。

 [[self getManagedObjectContext] insertObject:user]; 

在尝试完所有事情之后,慢慢地将现有代码减less到无,只是一个没有函数或pipe理器的直接内联版本 – 只是为了查明当我看到mainContext中的registeredObjects是在保存child-context之后,实际上是NOT一个空的元素…我终于find了答案。

事实certificate,我正在创build(有意的)在创build时不被pipe理(放在上下文中)的对象。 我的想法是,当我与REST-API /后端交stream时,我可以将JSON响应转换为对象(悬而未决,不带上下文),然后与我已经存储在模型pipe理器中的对象进行比较,检测更改并通知用户这些更改…

因此,我做了;

 //Create object "hanging" so that we can add it to context alter on... NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:mainContext]; User* user = (User *)[[User alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; 

…然后,当我决定这是新的东西,我想保持的东西;

 //Insert it [privateContext insertObject:user]; 

但是,插入的对象保存在子上下文中时,会自动合并到父代的主上下文中 – 清空! 但是,当我试图直接添加对象到私有上下文时,对象在合并期间突然没有被清空;

 //Create object AND insert into context now... NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:mainContext]; User* user = (User *)[[User alloc] initWithEntity:entity insertIntoManagedObjectContext:privateContext]; 

我不明白为什么,但真的。 合并对象在从子项的私有上下文合并到父项的主要上下文时为什么变空的原因。 我宁愿不是这样,因为这意味着我正在运行的“更改检测/通知”代码的大型重组,但是至less我是线程安全的,当涉及到CoreData;)