我对coredata中的多线程有一个疑问。如果我们使用多线程,我们应该使用单独的NSManagedObjectContext来插入新数据或更新,否则我们可以使用父子上下文方法。但我只创建新的NSManagedObjectContext。我的问题是,我是否应该使用单独的NSManagedObjectContext甚至在后台线程中获取。如果不是(即我们只能使用主队列NSManagedObjectContext),而不是为什么我得到__psynch_mutexwait错误。
谢谢,
答案 0 :(得分:17)
首先,Core Data是线程安全的。但是,您必须遵守以下规则:
NSManagedObjectContext
是线程绑定的。您只能在分配给它的线程上使用它。 -init
导致将上下文分配给创建它的线程。使用-initWithConcurrencyType:
将允许您创建与其他线程/队列关联的上下文。NSManagedObject
关联的任何NSManagedObjectContext
与其来自的上下文绑定到同一个线程/队列您可以在线程之间传递NSManagedObjectID
个实例,但必须遵守规则1和2。根据您的描述,我认为您违反了这些规则。
我个人也不建议使用NSManagedObjectID。有更好的解决方案。 - Marcus S. Zarra
Marcus,这是我读过的Core Data的线程最简洁的解释。自从它推出以来使用它,有几天我仍然会错误地遵守这些规则!你提到“更好的解决方案” - 你能详细说明吗?
我对使用NSManagedObjectID
有相当强烈的不信任感。在许多情况下,它在一个应用程序生命周期中不会保持不变。最初,根据文档,我们(一般的Cocoa开发人员)认为这是我们为我们生成的神秘主键。结果证明这是不正确的。
在具有父母/子女背景的现代发展中,景观更加令人困惑,我们需要注意一些有趣的陷阱。鉴于目前的情况,我比以前更不喜欢它。那我们用什么呢?
我们应该自己创造。它不需要太多。如果您的数据已经没有来自服务器的主键(从基于Ruby的服务器获得id
非常常见),那么创建一个。我想将其称为guid
,然后使用与此类似的-awakeFromInsert
:
- (void)awakeFromInsert
{
[super awakeFromInsert];
if (![self primitiveValueForKey:@"guid"]) {
[self setPrimitiveValue:[[NSProcessInfo processInfo] globallyUniqueString] forKey:@"guid"];
}
}
注意:此代码是在Web浏览器中编写的,可能无法编译。
您检查该值是因为每个上下文调用-awakeFromInsert
一次。那么我通常会在我的NSManagedObject
个实例上有一个方便的方法,类似于:
@implementation MyManagedObject
+ (MyManagedObject*)managedObjectForGUID:(NSString*)guid inManagedObjectContext:(NSManagedObjectContext*)context withError:(NSError**)error
{
NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:[self entityName]];
[fetch setPredicate:[NSPredicate predicateWithFormat:@"guid == %@", guid]];
NSArray *results = [context executeFetchRequest:request error:error];
if (!results) return nil;
return [results lastObject];
}
@end
注意:此代码是在Web浏览器中编写的,可能无法编译。
这使得错误处理和上下文/线程控制留给开发人员,但提供了一种方便的方法来检索当前上下文中的对象,并让我们将对象从一个上下文“反弹”到另一个上下文。
这比-objectWithID:
慢,应谨慎使用,并且仅在需要在保存向上移动堆栈后将对象从一个上下文反弹到另一个上下文的情况下使用。 / p>
和我做的大多数事情一样; 这不是通用的解决方案。这是一个基线,应该按项目进行调整。