核心数据iCloud同步中的关系完整性和验证

时间:2012-04-17 15:17:42

标签: macos cocoa core-data sync icloud

考虑以下简单实体模型:实体A与实体B的一对一关系称为 b 。实体B具有称为 a 的反向关系。两种关系都不是可选的。

A            B
b  < ----- > a

假设我们有两个设备(1)和(2)开始完全同步。每个都有一个A类对象和一个B类对象,它们彼此相关联。在设备1上,我们有对象A1和B1,在设备B上我们有相同的逻辑对象A1和B1。

现在假设在每台设备上进行了模拟更改:

  

在设备1上,我们删除B1,插入B2,并将A1与B2关联。然后   保存更改。
在设备2上,我们删除B1,插入B3,并关联A1   与B3。然后保存更改。

设备1现在尝试从设备2导入事务日志。将插入B3,并且A1将与B3关联。到目前为止一切都那么好,但是现在B2的关系 a 等于 nil a 关系是非可选的,因此会发生验证错误。

设备2上会发生类似的事情,因为有两个B对象,并且只有一个A对象要关联。因此必须始终存在验证错误,因为其中一个B对象必须将 a 关系设置为 nil

更糟糕的是,任何未来的更改都会留下错误的B对象,因此验证失败。实际上,用户无法通过重置关系来自行解决问题。它永久地被打破了。

问题是,如何解决这样的验证错误?这一切都发生在触发NSPersistentStoreDidImportUbiquitousContentChangesNotification通知之前。它不是您的应用程序主NSManagedObjectContext中的验证错误,它是在将事务日志初始导入持久性存储期间发生的验证错误。

我能想到的唯一选择可能是尝试删除B类本身的自定义setter(setA:)或KVC验证方法(validateA:error:)中的无效B对象,因为这些似乎在事务日志导入期间被触发。但我不确定是否允许这样的副作用,当我尝试它时,它确实会导致令人讨厌的日志消息。

任何人都知道处理这个问题的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

在Apple的开发者论坛上查看此主题:

https://devforums.apple.com/message/641930#641930

Apple员工的回复。简而言之:

1)这是在当前版本的iOS(5.1)和OS X(10.7.3)下Core Data iCloud同步中的一个已知错误。

2)如果关系对于验证谓词是非可选的,则同步将完全停止。因此,您需要删除有关时间的验证以保持流畅。但是,这样做会使设备的数据不匹配。

3)没有正式的解决方法。一种混乱的方法是保持跟踪关系的单独属性。然后,您需要扫描通过iCloud更改的任何对象,并修复关系,如果它是nil。

我也被这个错误所困扰。处理遇到麻烦的客户非常沮丧。希望很快得到Apple的修复......

答案 1 :(得分:1)

如果这有助于其他人,我在iCloud中解决了这个bug方面取得了一些进展。我所做的是在初始事务日志导入期间禁用验证,并在我的MOC保存到我的主存储时再次启用它。当然,我仍然会收到验证错误,但它们发生在我的MOC保存方法中,而不是深入到Core Data框架中,所以我可以修复错误(例如删除无效对象)。

如何“禁用”验证?我这样做的方法是覆盖我的NSManagedObject子类中的KVC验证方法,我已将其用作所有Core Data实体类的根类。

-(BOOL)validateValue:(__autoreleasing id *)value forKey:(NSString *)key error:(NSError *__autoreleasing *)error 
{
    if ( ![self.managedObjectContext isKindOfClass:[MCManagedObjectContext class]] ) {
        return YES;
    }
    else {
        return [super validateValue:value forKey:key error:error];
    }
}

在覆盖中,我检查托管对象上下文的类,如果它是我的自定义类,我通常通过链接到super方法进行验证。如果它不是我的自定义子类,我返回YES表示有效。

当然,你可以让这个更加细致,但你希望得到这个想法:你试图确定这是你的应用程序的标准保存或iCloud导入保存之一,并相应地进行分支。