【问题标题】:NSMergeConflict (two threads) - setting a merge policy doesn't solveNSMergeConflict(两个线程) - 设置合并策略并不能解决
【发布时间】:2013-02-22 12:21:41
【问题描述】:

好吧,这让我发疯了。

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

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

我遇到了 NSMergeConflict

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

在主线程上(在 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];

后来:

- (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);
        }];
}

在后台线程上:

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);

我尝试了所有类型的合并策略常量都无济于事。

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

冲突列表 = ( “NSManagedObject (0x119aea80) 的 NSMergeConflict (0x1a9ee1e0),objectID 为‘0x9dcec90’,oldVersion = 10 和 newVersion = 11,旧对象快照 = {\n displayName = \"\";\n machineName = KIYGRDRTTDVLTQB;\n note = \" \";\n 产品 = \"0x11967ab0 \";\n 公开 = 1;\n 已发布 = 1;\n 数量 = 3;\n 注册地址 = \"\";\n 注册地址 = \"\";\ 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 注册地址 = \"\";\n 注册地址 = \"\";\n 注册地址 = \"\";\n 状态 = \"在注册中\";\n upDate = \"2013-03-07 10:22:03 +0000\";\n wishList = \"\";\n}" ); }

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

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

谢谢大家

【问题讨论】:

    标签: ios multithreading cocoa-touch core-data conflict


    【解决方案1】:

    朋友们,

    一个月后,我对此心烦意乱 - 有一个解决方案,没有什么我会猜到的。实际上,我向 Apple 发起了一个支持事件,他们解决了这个问题。

    所以这里是:

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

    代替

       [self.mainManagedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
    

    我现在使用:

       NSManagedObjectContext *parentContext = delegate.mainManagedObjectContext.parentContext;
        [parentContext performBlockAndWait:^{
            [parentContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
        }];
    

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

    就个人而言,我必须添加两个大嘘声: 1. 对我嘘声,使用 NSManagedDocument 虽然有点过时,只是因为我找到了使用它的好例子。 2. 苹果在该领域非常缺乏文档。我花了数周时间阅读有关 ManagedObjectContexts 的内容,今天是我第一次了解 parentContext 属性。

    【讨论】:

    • 嗨@llan lewin,你能看看这个链接stackoverflow.com/questions/19443853/…
    • 首先感谢!这绝对解决了我的问题。关于父上下文,您可以在以下位置阅读它们:developer.apple.com/library/ios/documentation/DataManagement/…(部分:使用托管文档的托管对象上下文。)
    • 您好 Ilan,在您的回答中您提到了这种方法(即在 performBlockAndWait 中设置合并策略)在您通过创建 NSManagedDocument 获取上下文时很有用。我没有使用这个工作流程。我也应该在我的工作流程中添加它吗?或者还有其他方法吗?
    • 那么,合并策略总是必须在父 ctx 上设置?
    • 我们何时设置合并策略?什么时候?!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-08
    • 1970-01-01
    • 2020-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多