Core Data的NSPrivateQueueConcurrencyType和线程之间共享对象

时间:2011-12-26 17:45:29

标签: iphone core-data concurrency ios5

iOS 5引入了一种新方法,可以通过使用NSPrivateQueueConcurrencyType初始化MOC然后在performBlock:

中进行提取来快速获取后台线程上的数据

Core Data的一个经验法则是您无法在线程/队列之间共享托管对象。是performBlock:还是这样吗?如下:

[context performBlock:^{
    // fetch request code

    NSArray *results = [context executeFetchRequest:request error:nil];

    dispatch_async(dispatch_get_main_queue(), ^(void) {
        Class *firstObject = [results objectAtIndex:0];
        // do something with firstObject
    });
}];

仍然不能接受,因为我在bg队列和主队列之间共享我的结果数组/对象?我是否仍需要使用托管对象ID来执行此操作?

2 个答案:

答案 0 :(得分:66)

当您使用NSPrivateQueueConcurrencyType时,您需要执行任何触及上下文 -performBlock:方法中属于该上下文的任何对象。

上面的代码是非法的,因为您将这些对象传递回主队列。不过,新的API可以帮助您解决这个问题:您创建了一个与主队列关联的上下文,即使用NSMainQueueConcurrencyType

// Assume we have these two context (They need to be set up. Assume they are.)
NSManagedObjectContext *mainMOC = [[[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType] autorelease];
NSManagedObjectContext *backgroundMOC = [[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType] autorelease];

// Now this can safely be called from ANY thread:
[backgroundMOC performBlock:^{
    NSArray *results = [backgroundMOC executeFetchRequest:request error:nil];
    for (NSManagedObject *mo in results) {
        NSManagedObjectID *moid = [mo objectID];
        [mainMOC performBlock:^{
            NSManagedObject *mainMO = [mainMOC objectWithID:moid];
            // Do stuff with 'mainMO'. Be careful NOT to use 'mo'.
        }];
    }
}];

如果将内部[mainMOC performBlock:]调用移动到自己的方法中,则会减少混淆。您可能还希望将对象ID数组传递回主线程的上下文,而不是为每个对象ID执行一个块。这取决于你的需求。

答案 1 :(得分:3)

Daniel Eggert解释说,情况肯定如此。例外情况是NSMainQueueConcurrencyType,您还可以在主线程上安全地使用托管对象上下文和对象(以及通过performBlock机制从其他线程)。这个用处不容低估!

iOS 5还引入了父上下文的概念,这也大大简化了后台操作,并且无需担心使用通知来传播线程之间的更改。

WWDC 2012 video "Session 214 - Core Data Best Practices"详细介绍了这两个主题并且非常全面。对于使用Core Data的任何人来说,视频都是必不可少的。