Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在iOS 8中合并核心数据NSManagedObjectContext_Ios_Objective C_Core Data - Fatal编程技术网

在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方法访问上下文的任何部分,包括其对象及其属性,但上下文自己的访问器方法除外。