考虑以下简单实体模型:实体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对象,因为这些似乎在事务日志导入期间被触发。但我不确定是否允许这样的副作用,当我尝试它时,它确实会导致令人讨厌的日志消息。
任何人都知道处理这个问题的正确方法是什么?
答案 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导入保存之一,并相应地进行分支。