在iOS 8中合并核心数据NSManagedObjectContext
我使用的是“老派”核心数据并发模型。换句话说,我有一个主在iOS 8中合并核心数据NSManagedObjectContext,ios,objective-c,core-data,Ios,Objective C,Core Data,我使用的是“老派”核心数据并发模型。换句话说,我有一个主NSManagedObjectContext,它是用NSMainQueueConcurrencyType创建的,任何网络请求都会在新创建的NSPrivateQueueConcurrencyType上下文中处理JSON响应数据。上下文共享一个persistentstorecordinator,而不是使用parentContext,并且上下文合并是手动完成的 自从iOS 8以来,我的一些设备表现出一种行为,似乎上下文合并无法正常工作。在观察到一
NSManagedObjectContext
,它是用NSMainQueueConcurrencyType
创建的,任何网络请求都会在新创建的NSPrivateQueueConcurrencyType
上下文中处理JSON响应数据。上下文共享一个persistentstorecordinator
,而不是使用parentContext
,并且上下文合并是手动完成的
自从iOS 8以来,我的一些设备表现出一种行为,似乎上下文合并无法正常工作。在观察到一个NSManagedObjectContextDidSaveNotification
后,我正在通过调用主上下文上的mergeChangesFromContextDidSaveNotification
将更改合并到主上下文中。之后,我尝试使用objectWithID:
获取活动对象图的主要上下文版本,这看起来似乎有效。但是,在仔细检查返回的对象后,任何NSSet
关系都是空的,即使辅助上下文版本有它们*
奇怪的是,同样的代码在运行ios8的iphone6/6+上产生了精确的上下文合并。即使是我的iOS 7 iPod Touch 5G也能正常工作。持续出现故障的设备是相同的iOS 8 iPod Touch 5G。它也适用于所有模拟器
是否有其他人看到过类似的行为,或者对可能导致此设备特定核心数据问题的原因有所了解?提前谢谢
__block id toReturn = [self processResponse:responseData]; //Complete object graph from api.
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setPersistentStoreCoordinator:[self persistentStoreCoordinator]]; //shared PSC
[context setUndoManager:nil];
[context setStalenessInterval:0];
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
NSManagedObjectContext *mainContext = [self mainContext];
[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification
object:context
queue:[NSOperationQueue mainQueue]
usingBlock:
^(NSNotification *notification) {
[mainContext mergeChangesFromContextDidSaveNotification:notification];
NSManagedObjectID *managedId = [toReturn objectID];
NSManagedObject *mainContextVersion = [mainContext objectWithID:managedId];
toReturn = mainContextVersion; //*This is where the object graph is incomplete
}];
//Save context, will fire NSManagedObjectContextDidSaveNotification.
NSError *errorWhileSaving;
[context save:&errorWhileSaving];
我不会玩你似乎正在玩的游戏,它看起来像是从私有上下文中的托管对象开始,然后变成主上下文中的托管对象 您应该使用托管对象ID作为全局块变量(或者更好的是,根本不使用全局变量),这样您就不必窥视托管对象来获取它。我见过很多人声称不使用
performBlock
就可以获得ObjectID,但我从未接触过其performBlock
之外的任何MO/MOC。从未。曾经过去有太多头疼的事,所以我坚持自己的观点
__block NSManagedObjectID *toReturnObjectID;
但是,如果要这样做,必须首先从适当的上下文访问它。乍一看,像这样的事情。。。这很难看,但说明了这一点
[mainContext mergeChangesFromContextDidSaveNotification:notification];
[toReturn.context performBlock: ^{
NSManagedObjectID *managedId = [toReturn objectID];
[mainContext performBlock: ^{
NSManagedObject *mainContextVersion = [mainContext objectWithID:managedId];
toReturn = mainContextVersion; //*This is where the object graph is incomplete
// All the rest of the code that needs to happen...
另外,请注意,在其他上下文中调用save之后,对全局返回的任何访问都可能会带来麻烦。基本上,你不应该这样做。处理完成后,您已经发出通知。为什么不将toreReturn
放在通知用户信息中,而不是将其堆积到全局变量中?此外,您可以将ObjectID放在发布did save通知的上下文的userInfo中,并在触发通知时将其取出
如果让通知在其自己的线程中运行(而不是为块提供运行队列),则可以访问正在保存的MOC,因为您正在其活动线程/队列/上下文中运行。保存前将对象ID放入userInfo
类似于
[[NSNotificationCenter defaultCenter]
addObserverForName:NSManagedObjectContextDidSaveNotification
object:context
queue:nil
usingBlock:^(NSNotification *notification) {
// we can access the context here, since we are running in its notification
NSManagedObjectContext *context = [notification object];
NSManagedObjectID *managedId = [[context userInfo] objectForKey:@"ObjectGraphOID"];
// Now that we have the object ID, capture it in the block that will do the work...
[mainContext performBlock:^{
[mainContext mergeChangesFromContextDidSaveNotification:notification];
NSManagedObject *mainContextVersion = [mainContext objectWithID:managedId];
NSMutableDictionary *mainContextUserInfo =
[[self migratedInsertedObjectsDictionaryFromUserInfo:[notification userInfo]] mutableCopy];
// Pass the result as part of userInfo of the notification
mainContextUserInfo[@"ObjectGraph"] = mainContextVersion;
[[NSNotificationCenter defaultCenter]
postNotificationName:FPFlatpackCycleCompleted
object:self
userInfo:mainContextUserInfo];
}];
}];
你的第一段很好地概括了你的问题。它不是特定于设备的,它与使用队列限制和合并通知有关-它们不能很好地协同工作,如果您使用PerformLockandWait,由于缺乏用户事件处理,您将很难诊断问题。我没有使用PerformLockandWait。
您的意思是“你没用吗“@quellish?如果是这样,我的印象是,如果我使用父子上下文模型,我只需要使用performBlock
或performBlockAndWait
,因为save
是一个同步事件,只有在保存完成后才会触发通知。在任何情况下,我都尝试过在performBlockAndWait
块中包装save
和mergeChanges…
调用,结果没有变化。我的意思是“是”。如果使用的上下文不是通过NSConfinementConcurrencyType
创建的,则必须使用block方法访问上下文的任何部分,包括其对象及其属性,但上下文自己的访问器方法除外。