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来执行此操作?
答案 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的任何人来说,视频都是必不可少的。