我正在使用Core Data处理多线程应用。具有讽刺意味的是,当我得知Core Data不是线程安全的时候,我认为该应用程序即将完成...因此,我现在正在添加多上下文而不是我从Xcode模板中获得的单上下文(并且到目前为止一直工作,真的,但这比运气更有运气我想)
我正在尝试使用>具有父/子上下文的iOS 5.0方法很适合我正在尝试的内容,但是当我在子上下文中插入具有有效数据/属性的有效对象时,它们都变为nil或0(取决于属性)在父上下文中输入。
我注意到有类似的帖子,但没有任何答案;
Parent MOC get changes with empty data from child MOC
这是一些获得想法的代码;
我有一个单独的管理器,UI用来“做东西”,然后在任务完成时使用委托或回调。该经理反过来有一个模型经理来处理持久数据管理,还有一些其他的通信经理与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中的save函数考虑了context 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;
}
....
}
}
}
通过在保存子上下文和父/主上下文之前和之后添加调试打印,我注意到插入的对象很好地存在于子上下文中,并且子上下文说“hasChanges == YES”,而正如预期的那样,main-context说“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;
})
此后保存主要上下文,并在保存之前查看它的registeredObjects,我们可以看到“hasChanges == YES”(在孩子将插入的对象保存/合并到其父级之后预期。但是,此外 - 根据属性类型,所有参数和属性现在都为零或0;
(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”的所有各种组合但没有效果。
我甚至尝试过&lt;我在“mergeChangesFromContextDidSaveNotification”中添加NSNotificationCentre方法的iOS 5.0方法,我唯一可以验证的是,NSNotification参数中的数据是有效的和“好数据”,但主要上下文仍未正确更新。结果仍然是一个空对象。
期待您的想法和想法。
/马库斯
使用主上下文创建新托管对象时使用的代码,无论当时正在运行哪个线程/上下文执行块...
NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:self.mainManagedObjectContext];
User* user = (User *)[[User alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
此后,对象用户挂起时没有上下文,直到稍后我决定将其添加到托管上下文(使用我的 getManagedObjectContext 来指定正确/当前上下文)。
[[self getManagedObjectContext] insertObject:user];
答案 0 :(得分:0)
在尝试了所有内容之后,慢慢地将现有代码减少为空,只是一个没有函数或管理器的直接内联版本 - 只是为了确定在保存子上下文后我可以看到mainContext中的registeredObjects ,实际上不是一个空元素......我终于找到了答案。
事实证明,我正在创建(故意)在创建时未被管理(放入上下文)的对象。我的想法是,当我使用REST-API /后端时,我可以将JSON响应转换为对象(悬空,没有上下文),然后与我已经存储在模型管理器中的内容进行比较,以便我可以检测更改并通知用户这些更改......
因此,我做了;
//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];
我不明白为什么,真的,但确实如此。合并对象在从子级私有上下文合并到父级主上下文时被清空的原因。我宁愿这不是这种情况,因为这意味着我正在运行的“更改检测/通知”代码的大量重组,但至少我对CoreData来说是线程安全的;)