关于 MagicalRecord,MR_saveNestedContexts 和 MR_save 方法有啥区别

Posted

技术标签:

【中文标题】关于 MagicalRecord,MR_saveNestedContexts 和 MR_save 方法有啥区别【英文标题】:Regarding MagicalRecord, what is the difference between the methods MR_saveNestedContexts and MR_save关于 MagicalRecord,MR_saveNestedContexts 和 MR_save 方法有什么区别 【发布时间】:2012-11-09 00:08:03 【问题描述】:

在 MagicalRecord github 文档中指出:

MagicalRecord 提供了一个后台保存队列,以便保存所有 数据在后台的主线程中执行。这表示 可能需要使用 MR_saveNestedContexts 而不是 典型的 MR_save 方法,以便将您的更改一直保存到 你的持久存储。

查看源代码,我无法弄清楚这两种方法减去dispatch_async 命令后的区别。我看到它们都将所有嵌套上下文保存到根目录,因此保留到商店。但是为什么以及在什么情况下我会使用其中一种呢?

另外,就只是将嵌套上下文保存上一级(不持久存储)我假设我仍然会使用 NSManagedObjectContext 的- (BOOL)save:(NSError **)error 方法?

下面是这两种方法的源码。

- (void) MR_save 
    [self MR_saveErrorHandler:nil];


- (void) MR_saveErrorHandler:(void (^)(NSError *))errorCallback 
    [self performBlockAndWait:^
        [self MR_saveWithErrorCallback:errorCallback];

        if (self.parentContext) 
            [[self parentContext] performBlockAndWait:^
                [[self parentContext] MR_saveErrorHandler:errorCallback];
            ];
        
    ];


- (void) MR_saveNestedContexts 
    [self MR_saveNestedContextsErrorHandler:nil];


- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback 
    [self MR_saveNestedContextsErrorHandler:nil completion:nil];


- (void) MR_saveNestedContextsErrorHandler:(void (^)(NSError *))errorCallback completion:(void (^)(void))completion 
    [self performBlock:^
        [self MR_saveWithErrorCallback:errorCallback];

        if (self.parentContext) 
            [[self parentContext] performBlock:^
                [[self parentContext] MR_saveNestedContextsErrorHandler:errorCallback completion:completion];
            ];
         else 
            if (completion) 
                dispatch_async(dispatch_get_main_queue(), ^
                    completion();
                );
            
        
    ];

【问题讨论】:

【参考方案1】:

ios5 和 Lion 开始,CoreData 中新的父/子功能,有时需要“强制”保存到磁盘。也就是说,例如,当您有 3 个上下文时,例如:

root <- child1 <- child2

如果您保存在 child2 中,这些更改只会向上一级通知给 child1。 Root不会拥有它们。为此,您必须再调用一次 save。您可以拥有任意长的这些上下文列表这一事实意味着您将不知道您的保存是否会到达根上下文,它也负责对存储(磁盘)进行持久更改。 saveNestedContexts 使用递归来遍历这棵树,并确保您的保存确实在您打算这样做时进入磁盘。

【讨论】:

对,但是从源代码来看,这两种方法都是通过if (self.parentContext) ... 递归到根目录并通过[self MR_saveWithErrorCallback:errorCallback]; 保存的。所以看起来 MR_save 也在做同样的事情。【参考方案2】:

'MR_save' 和 'MR_saveNestedContexts' 之间的相似性在 2.0.8 版本中发生了变化(我使用的是 2.0.7)。

这是 github 上的提交:https://github.com/magicalpanda/MagicalRecord/commit/f7c4350e9daf7d90eec83ba5eafeccfa7af34312

还有讨论:https://github.com/magicalpanda/MagicalRecord/issues/305

总而言之,在 2.0.8 版本中,“MR_save”现在只保存当前上下文,而“MR_saveNestedContexts”递归地保存到最顶层的上下文。

【讨论】:

其实没那么简单。 MR_save 确实等待保存完成。 MR_saveNestedContexts 完全异步并立即返回。所以它们并不完全是重复的。见:github.com/magicalpanda/MagicalRecord/issues/318

以上是关于关于 MagicalRecord,MR_saveNestedContexts 和 MR_save 方法有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

使用 MagicalRecord 有效保存

使用 MagicalRecord 进行核心数据加密

MagicalRecord:[MagicalRecord saveWithBlock] 中的死锁

在并发 NSOperation (MagicalRecord-2.3) 中使用 MagicalRecord 的正确方法

MagicalRecord:后台保存

Magical Record - 在主线程块 ui 中获取,在后台返回 nil