6

考虑以下简单的实体模型:实体 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等于nila关系是非可选的,因此会发生验证错误。

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

更糟糕的是,任何未来的更改都会留下一个错误的 B 对象,因此验证失败。实际上,用户不能通过重置关系自己解决问题。它永久损坏。

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

我能想到的唯一选择可能是尝试在自定义设置器setA:validateA:error:. 但是我不确定是否允许这样的副作用,当我尝试它时,它似乎确实会导致令人讨厌的日志消息。

有谁知道处理这个问题的正确方法是什么?

4

2 回答 2

2

在 Apple 的开发者论坛上查看此线程:

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

有苹果员工的回应。简而言之:

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

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

3)没有官方的解决方法。一种混乱的方法是维护一个单独的属性来跟踪关系。然后,您需要扫描通过 iCloud 更改的所有对象,如果它为 nil,则修复关系。

我也被这个虫子咬了。与遇到麻烦的客户打交道非常令人沮丧。希望Apple的修复程序很快就会出来......

于 2012-04-17T23:51:38.467 回答
1

如果这对其他人有帮助,我在 iCloud 中解决此错误方面取得了更多进展。我所做的是在初始事务日志导入期间禁用验证,并在我的 MOC 保存到我的主商店时再次启用它。当然,我仍然会遇到验证错误,但它们发生在我的 MOC 保存方法中,而不是在核心数据框架的深处,因此我可以修复错误(例如删除无效对象)。

如何“禁用”验证?我这样做的方式是覆盖我的 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];
    }
}

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

当然,您可以使这更加细微,但希望您能明白:您尝试确定这是您的应用程序的标准保存之一还是 iCloud 导入保存,并相应地进行分支。

于 2012-04-18T10:25:38.177 回答