NSMergeConflict(两个线程) - 设置合并策略无法解决

Ila*_*win 8 multithreading cocoa-touch conflict core-data ios

好的,这让我疯了.

我有两个使用UImanageddocument的线程,一个在用户进行选择的主上下文中,后台线程有自己的moc,根据时间戳将数据与服务器同步.

所有似乎都运行良好,但是当我:1.在主上下文中添加一个对象2.在后台同步3.从后台保存4.尝试再次更改同一个对象,现在从主上下文 - 主线程

我得到了一个N​​SMergeConflict

我将包括一些我的代码,排除很多不相关的代码,向您展示我如何初始化上下文,希望有人可以启发我.我知道这些领域的核心数据很棘手.

在主线程上(在applicationdidfinishloadingwithoptions中):

    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject]; //get the default user documents folder
    url = [url URLByAppendingPathComponent:DATABASENAME];
    UIManagedDocument *doc = [[UIManagedDocument alloc] initWithFileURL:url];
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
    doc.persistentStoreOptions = options;
    [doc.managedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
    self.database=doc;
    self.mainManagedObjectContext=self.database.managedObjectContext;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDataModelChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:self.database.managedObjectContext];
Run Code Online (Sandbox Code Playgroud)

然后:

- (void)handleDataModelChange:(NSNotification *)note
{
    [self save];
}

-(void) save
{
        [self.database saveToURL:self.database.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success) {
            batch_save=!success;
            NSLog(@"save success %d",success);
        }];
}
Run Code Online (Sandbox Code Playgroud)

并在后台线程:

dispatch_queue_t fetchQ = dispatch_queue_create("syncing list", NULL);
dispatch_async(fetchQ, ^   // ***********  BACKGROUND THREAD ***********
{
    AppDelegate *delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
    NSManagedObjectContext *backgroundMOC2;
    backgroundMOC2=[[NSManagedObjectContext alloc] init];
    [backgroundMOC2 setPersistentStoreCoordinator:delegate.mainManagedObjectContext.persistentStoreCoordinator];
    [backgroundMOC2 setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
    [delegate.mainManagedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
    [[NSNotificationCenter defaultCenter] addObserver:delegate.mainManagedObjectContext selector:@selector(mergeChangesFromContextDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:backgroundMOC2];


    ** pseudo-code: 
       perform fetch request from CD
       submit data to server with POST request (synchronously)
       retrieve JSON reply from server
       update what's needed in CD objects
    ** end of pseudo code

   [backgroundMOC2 save:nil];
   [[NSNotificationCenter defaultCenter] removeObserver:delegate.mainManagedObjectContext name:NSManagedObjectContextDidSaveNotification object:backgroundMOC2];
    });
dispatch_release(fetchQ);
Run Code Online (Sandbox Code Playgroud)

我已经尝试了所有类型的合并策略常量无济于事.

我收到了这个,文件没有保存:

conflictList =(NSMergeConflict(0x1a9ee1e0)for NSManagedObject(0x119aea80)with objectID'0x9dcec90'with oldVersion = 10 and newVersion = 11 and old object snapshot = {\n displayName = \"\"; \n machineName = KIYGRDRTTDVLTQB; \n note = \"\"; \n产品= \"0x11967ab0 \"; \n public = 1; \n已发布= 1; \n数量= 3; \n registeredTo = \"\"; \n registeredToEmail = \"\ "; \n registeredToNote = \"\"; \n status = \"ON REGISTRY \"; \n upDate = \"2013-03-07 10:22:01 +0000 \"; \n wishList = \"\ "; \n}和新的缓存行= {\n displayName = \"\"; \n machineName = KIYGRDRTTDVLTQB; \n note = \"\"; \n product = \"0x1a9ee3d0 \"; \n public = 1 ; \n已发布= 1; \n数量= 3; \n registeredTo = \"\"; \n registeredToEmail = \"\"; \n registeredToNote = \"\"; \n status = \"ON REGISTRY \" ; \n upDate = \"2013-03-07 10:22:03 +0000 \"; \n wishList = \"\"; \n}"); }

顺便说一句,我看到旧对象和新对象之间的唯一区别是指向"产品"的指针.这可能是我的问题吗?

另一个可能的线索是,这种情况只会在添加新对象时发生,并且仅在后台同步发生之后发生.如果我停止应用程序并重新加载它(重新加载持久存储),我现在可以毫无问题地编辑现有对象,并且可以根据需要多次同步它,没有任何问题.

多谢你们

Ila*_*win 19

好朋友,

经过一个月的思考之后 - 有一个解决方案,我猜不出任何东西.我实际上与Apple开了一个支持事件,他们解决了这个问题.

所以这里:

为主要托管对象上下文设置合并策略时,有一个名为parentContext的属性.我仍然不太清楚这个属性是什么,因为文档很少见.然而,这绝对解决了我的问题.请考虑在我的工作流程中,我创建一个NSManagedDocument并从中提取上下文.我认为大多数人都是这样做(大多数人不使用托管文档).

代替

   [self.mainManagedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
Run Code Online (Sandbox Code Playgroud)

我现在用:

   NSManagedObjectContext *parentContext = delegate.mainManagedObjectContext.parentContext;
    [parentContext performBlockAndWait:^{
        [parentContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
    }];
Run Code Online (Sandbox Code Playgroud)

块事物是一个预防措施,以确保在正确的线程中执行此操作,重要的是将合并策略设置为所需上下文的parentContext.

在个人方面,我必须添加两个大嘘声:1.对我来说,使用NSManagedDocument,虽然它有点过时,只是因为我找到了使用它的好例子.对于苹果公司而言,该领域的文档非常缺乏.我花了几周阅读ManagedObjectContexts,今天是我第一次认识parentContext属性.