使用 iCloud 解决核心数据中的冲突

Posted

技术标签:

【中文标题】使用 iCloud 解决核心数据中的冲突【英文标题】:Resolving Conflicts in Core Data with iCloud 【发布时间】:2013-02-06 15:32:19 【问题描述】:

我正在编写一个使用 Core Data 并与 iCloud 同步的应用程序。为此,我设置了一个 UIManagedDocument,如下所示:

UIManagedDocument *document = [[UIManagedDocument alloc] initWithFileURL:[self iCloudStoreURL]];
        document.persistentStoreOptions = @NSPersistentStoreUbiquitousContentNameKey: [document.fileURL lastPathComponent], NSPersistentStoreUbiquitousContentURLKey: [self iCloudCoreDataLogFilesURL], NSMigratePersistentStoresAutomaticallyOption: @YES, NSInferMappingModelAutomaticallyOption : @YES;
        self.mydoc = document;
        [document release];

        [document.managedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(documentContentsChanged:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:document.managedObjectContext.persistentStoreCoordinator];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(documentStateChanged:) name:UIDocumentStateChangedNotification object:document];


        if (![[NSFileManager defaultManager] fileExistsAtPath:[self.mydoc.fileURL path]]) 
            // does not exist on disk, so create it
            [self.mydoc saveToURL:self.mydoc.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) 
                [self populateTable];//synchronous call. few items are added
                [self iCloudIsReady];
            ];
         else if (self.mydoc.documentState == UIDocumentStateClosed) 
            // exists on disk, but we need to open it
            [self.mydoc openWithCompletionHandler:^(BOOL success) 
                [self iCloudIsReady];
            ];
         else if (self.mydoc.documentState == UIDocumentStateNormal) 
            // already open and ready to use
        
    

我对这种方法的问题是,在两台设备上运行应用程序时,我不断收到“乐观锁定失败”。我在 Apple 的核心数据文档中读到,“避免”此类问题的一种方法是将合并策略设置为 NSMergeByPropertyObjectTrumpMergePolicy,我已经在这样做但由于某种原因无法正常工作。

我找不到的一件事是如何解决这个问题。例如,如果这是可能发生的事情,我的应用程序至少应该意识到并准备好处理这种行为。但我不知道如何处理这个问题。例如,如何获取冲突对象并解决它们?因为每次发生此故障时,我都会在尝试保存文档时开始收到 UIDocumentStateSavingError,而停止收到此错误的唯一方法是终止应用并重新启动它。

【问题讨论】:

为什么会出现这个问题?您是否看到数据损坏或其他不良行为? 这是一个问题有两个原因。一,两个设备之间的数据变得不同。二、收到故障的设备在关闭应用之前无法保存文档。 我没怎么用过UIManagedDocument,但它有两个嵌套的托管对象上下文,它的managedObjectContext 只获取子上下文。也许您需要在父上下文中设置它? 关闭应用如何解决失败?听起来您的托管对象上下文已过时,这意味着您没有正确响应导入通知。 我猜想通过关闭应用程序,托管对象会丢弃任何触发此故障的对象。确切地说,正如我在问题中所说,我不知道如何处理这个问题。如果有这种故障的通知,我不知道是哪一个。 【参考方案1】:

我终于想通了(至少,我想我做到了)。显然,在 ios6+ 上(我不知道 iOS5) UIManagedDocument 会为你处理所有的合并。所以,下面只负责调用“mergeChangesFromContextDidSaveNotification:”的观察者实际上是在合并刚刚合并的内容。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(documentContentsChanged:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:document.managedObjectContext.persistentStoreCoordinator];

...

- (void)documentContentsChanged:(NSNotification *)notification 
      [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];

调用“mergeChangesFromContextDidSaveNotification:”是负责触发“乐观锁定失败”的行。我删除了它,一切都开始按预期工作。不幸的是,这只持续了几个小时。现在我不断收到“iCloud Timed Out”错误,但我确定这是 Apple 的错。

无论如何,经过大量错误和三种不同的 iCloud + Core Data 方法,我想我会坚持将 iCloud 集成到我的应用程序中。它太不稳定和错误。我真希望苹果能在 iOS6 上解决这个问题,iCloud + Core Data 是一个非常强大的工具,不幸的是,它还没有准备好。

感谢所有试图提供帮助的人。

【讨论】:

以上是关于使用 iCloud 解决核心数据中的冲突的主要内容,如果未能解决你的问题,请参考以下文章

iCloud-CoreData 解决冲突

将核心数据与 iCloud 同步 - 不包括实体

IOS - iCloud中的核心数据备份

iCloud 中基于 SQLite 的核心数据中的有序关系

如何阻止核心数据同步到 iCloud

如何将现有核心数据 iOS 7 应用程序的数据迁移到 iCloud?