具有多个(线程)上下文的核心数据唯一属性

时间:2012-09-21 08:55:49

标签: ios objective-c core-data grand-central-dispatch

我正在使用Core Data unique attributes中描述的方法来防止两次使用相同的属性(此处属性称为ID)。

这在单线程环境中工作正常。我使用多线程环境并使用每个线程范例的一个上下文。

问题是如果两个线程同时尝试创建具有相同属性的对象,则存在以下问题:

  • 线程A在context1中创建ID为1的对象,没有这样的对象,因此它被创建
  • 线程B在context2中创建ID为1的对象,没有这样的对象,因此它被创建
  • 线程A同步context1-> context2(使用下面的代码)

您发现自己有两个具有相同ID(1)的记录。

我在测试时看到了这个问题,所以很少见,但肯定会随着时间的推移而发生。

当然,有很多选项,比如GDC,信号量可以防止这种情况发生,但在使用复杂的解决方案之前,我想知道是否有人有更好的解决方案,或者可以建议在什么级别来序列化事件。 / p>

使用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;
}

1 个答案:

答案 0 :(得分:0)

我认为我找到了解决方案,仅使用Core Data。

我现在正在使用NSLock来锁定上下文以模拟某种事务:

[[self managedObjectContextForThread] tryLock];

... read if ID1 exists ...

... write ID1 ...

[[self managedObjectContextForThread] unlock];

这似乎解决了这个问题(暂时)。