在不同的线程上访问NSManagedObject的objectID?

时间:2013-07-30 22:12:27

标签: ios core-data grand-central-dispatch nsmanagedobject nsmanagedobjectcontext

我的UITableViewCell内容创建的一部分因一个对象(CoreData NSManagedObject)初始访问时发生的错误而延迟。这表现在一个小的打嗝,细胞首先滚动到视图中。我决定将这些对象的访问权限推送到后台线程。

这是我实现它的方式并且它运行良好,但是我们都知道我们不应该在另一个线程中访问一个线程(主线程)的NSManagedObjectContext,但是我们可以在一个线程中获取一个对象的objectID第二个线程,如果它最初是在第一个线程中获取的?

获取objectID需要花费少量时间,我希望将其他所有内容都推到后台。

MyRecord *record = [self.frc objectAtIndexPath: indexPath];

// Should the following be here or can it be below in the background thread?
// NSManagedObjectID *recordObjectID = record.objectID;

dispatch_async(_recordViewQueue, ^(void) {
    if ([cell.origIndexPath isEqual:indexPath]) {

        // should the following be here or above?  It works here, but am I just lucky?
        // this call seems to take about 2/100 of a second
        NSManagedObjectID *recordObjectID = record.objectID;

        NSManagedObjectContext *bgndContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
        bgndContext.persistentStoreCoordinator = App.sharedApp.storeCoordinator;
        MyRecord *newRecord = (MyRecord *) [bgndContext objectWithID:recordObjectID];

        [self updateCell:cell withRecord:newRecord];

        if ([cell.origIndexPath isEqual:indexPath]) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [(UIView*) cell.recordView setNeedsDisplay];
            });
        }
    }
});

这样安全吗?或者我必须在mainThread中获取objectID吗?

1 个答案:

答案 0 :(得分:5)

在线程之间传递托管对象的objectID是安全的。在线程之间使用托管对象是不安全的。使用objectID和线程的托管对象上下文来调用existingObjectWithID:error:获取该线程的托管对象的实例。

我会更新你的代码:

MyRecord *record = [self.frc objectAtIndexPath: indexPath];

NSManagedObjectID *recordObjectID = record.objectID;

dispatch_async(_recordViewQueue, ^(void) {
    if ([cell.origIndexPath isEqual:indexPath]) {

        NSManagedObjectContext *bgndContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
        bgndContext.persistentStoreCoordinator = App.sharedApp.storeCoordinator;
        NSError * error = nil;
        MyRecord *newRecord = (MyRecord *) [bgndContext existingObjectWithID:recordObjectID error:&error];
        if (newRecord) {
            [self updateCell:cell withRecord:newRecord];
            if ([cell.origIndexPath isEqual:indexPath]) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [(UIView*) cell.recordView setNeedsDisplay];
                });
            }
        }
        else {
            NSLog(@"unable to find existing object! error: %@ (userInfo: %@)", [error localizedDescription], [error userInfo]);
        }
    }
});