我正在使用嵌套上下文模式来支持多线程下的CoreData工作。 我有一个名为CoredDataManager的单例类,其中上下文的初始化如下:
self.masterContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.masterContext.persistentStoreCoordinator = self.persistentStoreCoordinator;
self.mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
self.mainContext.parentContext = self.masterContext;
对于从Web服务返回的每个插入操作,我使用CoreDataManager的API来获取新的托管上下文:
- (NSManagedObjectContext *)newManagedObjectContext {
NSManagedObjectContext *workerContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
workerContext.parentContext = self.mainContext;
return workerContext;
}
它看起来像这样(PlayerView类是NSManagedObject类的子类):
[PlayerView insertIfNeededByUniqueKey:@"playerViewId" value:playerViewId inBackgroundWithCompletionBlock:^(NSManagedObjectContext *context, PlayerView *playerView) {
playerView.playerViewId = playerViewId;
playerView.username = playerViewDictionary[@"name"];
[context saveContextWithCompletionBlock:^{
//do something
} onMainThread:NO];//block invocation on background thread
}];
saveContextWithCompletionBlock方法是在NSManagedObjectContext类别中实现的:
- (void)saveContextWithCompletionBlock:(SaveContextBlock)completionBlock onMainThread:(BOOL)onMainThread {
__block NSError *error = nil;
if (self.hasChanges) {
[self performBlock:^{
[self save:&error];
if (error) {
@throw [NSException exceptionWithName:NSUndefinedKeyException
reason:[NSString stringWithFormat:@"Context saving error: %@\n%@\n%@", error.domain, error.description, error.userInfo]
userInfo:error.userInfo];
}
if (completionBlock) {
if (onMainThread && [NSThread isMainThread]) {
completionBlock();
} else if (onMainThread) {
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock();
});
} else if ([NSThread isMainThread]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul), ^{
completionBlock();
});
} else {
completionBlock();
}
}
}];
}
}
然后,在某个阶段,我会调用CoreDataManager的方法来保存主上下文:
- (void)saveMasterContext; {
__block NSError *error;
[self.mainContext performBlock:^{
[self.mainContext save:&error];
[self treatError:error];
[self.masterContext performBlock:^{
[self.masterContext save:&error];
[self treatError:error];
}];
}];
}
我有两个主要的类,它们都是NSManagedObject的子类 - PlayerView和Post。 PlayerView与Post之间具有一对多的关系。 PlayerView已保存并且没有问题。而Post从未被保存,我得到了以下错误:
CoreData: error: Mutating a managed object 0x17dadd80 (0x17daf930) after it has been removed from its context.
我认为问题在于上下文保存逻辑。