我正在使用Core Data 唯一属性中描述的方法来防止两次具有相同的属性(该属性在此处称为 ID)。
这在单线程环境中运行良好。我使用多线程环境并使用每个线程范例一个上下文。
问题是如果两个线程同时尝试创建具有相同属性的对象,就会出现以下问题:
- 线程 A 在 context1 中创建 ID 为 1 的对象,没有这样的对象,所以它被创建
- 线程 B 在 context2 中创建 ID 为 1 的对象,没有这样的对象,所以它被创建
- 线程 A 同步 context1->context2(使用下面的代码)
您发现自己有两条具有相同 ID (1) 的记录。
我在测试时看到了这个问题,所以它很少见,但随着时间的推移肯定会发生。
当然,有多种选择,如 GDC、信号量来防止这种情况发生,但在使用复杂的解决方案之前,我想知道是否有人有更好的解决方案,或者可以推荐在什么级别序列化事件。
使用 iOS5+ 和 ARC。
我使用此代码来同步我的上下文:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backgroundContextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:nil];
和:
- (void)backgroundContextDidSave:(NSNotification *)notification {
/* Make sure we're on the main thread when updating the main context */
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(backgroundContextDidSave:)
withObject:notification
waitUntilDone:NO];
return;
}
/* merge in the changes to the main context */
for (NSManagedObjectContext* context in [self.threadsDictionary allValues]){
[context mergeChangesFromContextDidSaveNotification:notification];
}
}
要获得线程安全的上下文:
/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *) managedObjectContextForThread {
// Per thread, give one back
NSString* threadName = [NSString stringWithFormat:@"%d",[NSThread currentThread].hash];
NSManagedObjectContext * existingContext = [self.threadsDictionary objectForKey:threadName];
if (existingContext==nil){
existingContext = [[NSManagedObjectContext alloc] init];
[existingContext setPersistentStoreCoordinator: [self persistentStoreCoordinator]];
[self.threadsDictionary setValue:existingContext forKey:threadName];
[existingContext setMergePolicy:NSOverwriteMergePolicy];
}
return existingContext;
}