由于MR_contextForCurrentThread对操作不安全(并且已被弃用),我试图确保我理解并发操作中一系列读/写的最佳模式。
建议使用saveWithBlock来存储新记录,并且可能是删除,它提供了使用的上下文。 Count和fetch方法可以给出一个上下文,但默认情况下仍然使用MR_contextForCurrentThread。
最安全的模式是在操作开始时使用[NSManagedObjectContext MR_context]获取上下文,并将其用于所有操作。该操作取决于某些异步工作,但不会长时间运行。然后在操作完成后执行MR_saveToPersistentStoreWithCompletion?
答案 0 :(得分:2)
使用NSOperation的原因是什么?这里有两个选择:
使用MagicalRecord的后台保存块:
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
// Do your task for the background thread here
}];
另一个选项是(正如您已经尝试过的)将其捆绑到NSOperation中。是的,我会使用[NSManagedObjectContext MR_newContext]
缓存一个私有队列上下文的实例(抱歉,我今天下午弃用了MR_context
方法,转而采用更清晰的替代方法)。请注意,除非您手动合并来自其他上下文的更改,否则您创建的专用队列上下文将是您创建它时的父上下文的快照。通常,这对于短期运行的后台任务来说不是问题。
托管对象上下文非常轻巧且便宜 - 只要您要在主线程以外的任何线程上工作,只需初始化并使用新上下文。它让事情变得简单。就个人而言,我赞成+ saveWithBlock:
及相关方法 - 它们很简单。
希望有所帮助!
答案 1 :(得分:1)
如果您愿意,则无法使用多个线程中的saveWithBlock
(并发NSOperations
):
这是因为无论何时使用saveWithBlock
创建新的本地上下文,都会在同一时间创建多个上下文,并且他们不知道彼此之间的更改。正如Tony提到的那样localContext
是rootContext
的快照,更改仅在一个方向上进行,从localContext
到rootContext
,但反之亦然。
这是一种同步调用saveWithBlock
的线程保存(甚至是MagicalRecord的一致性安全)方法:
@implementation MagicalRecord (MyActions)
+ (void) my_saveWithBlock:(void(^)(NSManagedObjectContext *localContext))block completion:(MRSaveCompletionHandler)completion;
{
static dispatch_semaphore_t semaphore;
static dispatch_once_t once;
dispatch_once(&once, ^{
semaphore = dispatch_semaphore_create(1);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[MagicalRecord saveWithBlock:block
completion:^(BOOL success, NSError *error) {
dispatch_semaphore_signal(semaphore);
if (completion){
completion(success, error);
}
}];
});
}
@end