我一直在为同样的问题苦苦挣扎。到目前为止,对这个问题的讨论给了我一些想法,现在我将分享。
请注意,由于在我的情况下,我只在测试过程中很少看到这个重复问题,而且没有明显的方法可以轻松地重现它,因此本质上是未经测试的。
我有相同的CoreData堆栈设置 - 在私有队列上拥有主MOC,该主MOC具有子MOC并用作应用程序的主要上下文。最后,使用后台队列将批量导入操作(查找或创建)传递给第三个MOC。完成操作后,保存将向PSC传播。
我已将所有Core Data堆栈从AppDelegate移动到一个单独的类(AppModel
),该类提供了访问域的聚合根对象(Player
)以及在模型上执行后台操作的帮助函数(performBlock:onSuccess:onError:
)。
对我来说,幸运的是,所有主要的CoreData操作都通过这个方法进行漏斗,因此如果我能确保这些操作按顺序运行,则可以解决重复问题。
- (void) performBlock: (void(^)(Player *player, NSManagedObjectContext *managedObjectContext)) operation onSuccess: (void(^)()) successCallback onError:(void(^)(id error)) errorCallback
{
[self.operationQueue addOperationWithBlock:^{
NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[managedObjectContext setUndoManager:nil];
[managedObjectContext setParentContext:self.mainManagedObjectContext];
[managedObjectContext performBlockAndWait:^{
id player = [managedObjectContext objectWithID:[self.player objectID]];
operation(player, managedObjectContext);
NSError *error = nil;
if (![managedObjectContext save:&error])
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%@", error);
if(errorCallback) return errorCallback(error);
});
return;
}
[managedObjectContext.parentContext performBlockAndWait:^{
NSError *error = nil;
if (![managedObjectContext.parentContext save:&error])
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%@", error);
if(errorCallback) return errorCallback(error);
});
return;
}
}];
[managedObjectContext reset];
dispatch_async(dispatch_get_main_queue(), ^{
if (successCallback) return successCallback();
});
}];
}];
}
我希望我添加的内容能解决我的问题,那就是将整个操作包装在
addOperationWithBlock
中。我的操作队列只是简单地配置如下:
single.operationQueue = [[NSOperationQueue alloc] init]
[single.operationQueue setMaxConcurrentOperationCount:1]
在我的API类中,我可能会执行以下操作导入我的操作:
- (void) importUpdates: (id) methodResult onSuccess: (void (^)()) successCallback onError: (void (^)(id error)) errorCallback
{
[_model performBlock:^(Player *player, NSManagedObjectContext *managedObjectContext) {
} onSuccess:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (successCallback) return successCallback();
});
} onError:errorCallback];
}
现在使用
NSOperationQueue
,就不可能同时进行多个批处理操作了。