核心数据合并行为

Posted

技术标签:

【中文标题】核心数据合并行为【英文标题】:Core Data merge behaviour 【发布时间】:2012-11-13 11:58:58 【问题描述】:

我试图找到这个问题的答案,但我无法从文档和 *** 中找出问题。如果已经有这样的问题,我只是没有找到它,所以它会非常欢迎作为以防万一的解决方案。

我的情况是: 我有两个核心数据实体,一个用户和一个驾驶执照。

User  <--- 1 to 1 ---> Driving Licence

我使用Magical Record 作为核心数据操作的抽象层。

我的用户类(从 NSManagedObject 派生)公开了 2 个方法。

一个访问用户的单例实例(整个应用程序中唯一使用的一个):

+ (User *)currentUser 

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
        if ([User MR_findFirst] == nil) 

            User *user = [User MR_createEntity];
            user.drivingLicence = [DrivingLicence MR_createEntity];
            [[user managedObjectContext] MR_save];
        
    );

    return [User MR_findFirst];

还有一个用来重置用户数据的方法(来源于NSManagedObject):

- (void)resetFields

   self.name = nil;
   self.surname = nil;
   ....
   [self.drivingLicence MR_deleteEntity];
   self.drivingLicence = [DrivingLicence MR_createEntity];
   [self.managedObjectContext MR_save];

有时,我会很随意地说,drivingLicence 字段恰好为空。 可能会有后台线程调用 resetFields 方法的情况。

难道是为了与其他上下文合并,指令序列

   [self.drivingLicence MR_deleteEntity];
   self.drivingLicence = [DrivingLicence MR_createEntity];

会导致一些混乱,导致驾驶执照最终被删除? 或者这个意外的空值还有什么原因?

【问题讨论】:

【参考方案1】:

当您使用 MR_createEntity 时,您会隐式使用默认上下文,通过 [NSManagedObjectContext MR_defaultContext] 访问。除非您绝对积极地从主线程调用它,否则这样做是非常危险的。在您的示例中,如果从主线程调用所有内容并且您的 self.managedObjectContext 实例变量也指向默认上下文,则所有这些都应该正常工作。否则,您将需要明确说明您正在使用哪些上下文。 MagicalRecord 通过在每个需要上下文才能工作的方法末尾添加一个 inContext: 可选参数来为您提供这些约定。查看 MR_createInContext: 方法并明确使用上下文

【讨论】:

【参考方案2】:

刚刚遇到这个问题。根据我们的发现,我想在上面casademora 的答案中添加一些 cmets:

重要的是要记住核心数据以及任何MR_save 方法都不是线程安全的。我们将 MagicalRecord 操作委托给队列以解决此问题。具体来说,重要的是要记住不要同时在多个线程中执行保存操作(例如MR_saveToPersistentStoreAndWait)。

但是MR_createEntityMR_defaultContextMain 线程之间的联系更加微妙。从 MagicalRecord 版本 2.3.x 开始,我不相信 MR_createEntity,没有参数,默认为 MR_defaultContext。我相信它默认为MR_contextForCurrentThreadMR_contextForCurrentThread 如果它在 Main 线程上,则返回默认上下文,否则不返回。如果您不了解后果,这是很危险的,因为您可以很容易地看到原始海报在上面看到的内容(丢失的数据)。

其实this note表示你应该使用MR_createEntityInContext:localContext而不是MR_createEntity,因为使用GCDMR_contextForCurrentThread有问题。

请参阅 github 中的 the function definition,了解 MR_createEntity 使用 MR_contextForCurrentThread 的逻辑。

【讨论】:

以上是关于核心数据合并行为的主要内容,如果未能解决你的问题,请参考以下文章

区间dp -- 典型模板,石子合并

P1880 石子合并

NOI 1995 合并石子 区间DP

合并冲突核心数据

核心数据与用于核心数据的单个 MOC 和主线程合并冲突

核心数据更改不合并