我有NSOperationQueue
添加了一些NSBlockOperations
,其中包括blockOperations A和B. NSOperationQueue
的{{1}}为1。
blockOperation B,依赖于A完成。在每个blockOperations中,我调用一个方法,该方法又调用另一个方法,初始化一个新的maxConcurrencyOperationCount
(使用来自单例的persistentStoreCoordinator),我用它来创建和添加对象到Core Data数据库。 A和B中前面提到的第二个方法调用调用的代码看起来像这样(它们每个都略有不同):
NSManagedObjectContext
NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
managedObjectContext.persistentStoreCoordinator = [[CoreDataController sharedCoreDataController] persistantStoreCoordinator];
for (NSDictionary *articleDictionary in array) {
if (![Article articleExistsWithIDInDictionary:articleDictionary inContext:managedObjectContext]) {
[Article articleFromDictionary:articleDictionary inContext:managedObjectContext];
}
}
[[CoreDataController sharedCoreDataController] saveContext:managedObjectContext];
// method ends.
代码如下所示:
saveContext:
花了很多时间阅读关于核心数据并发,NSOperation等的Apples Docs,我仍然不确定我使用NSManagedObjectContext做什么是线程安全的,通常被认为是正常的?我将非常感谢一些澄清和/或表明我应该采取不同的做法。如果您需要查看更多代码,请询问。
提前致谢。
答案 0 :(得分:4)
你在做什么不是线程安全的。
如果决定为每个操作创建一个上下文,最好使用限制并发类型:
context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
这样您就不需要更改当前代码中的任何内容。
如果您想将上下文与NSPrivateQueueConcurrencyType
一起使用,则必须通过performBlock:
或performBlockAndWait:
或[managedObjectContext performBlockAndWait:^{//wait is used as to not end the operation before this code is executed
for (NSDictionary *articleDictionary in array) {
if (![Article articleExistsWithIDInDictionary:articleDictionary
inContext:managedObjectContext])
{
[Article articleFromDictionary:articleDictionary
inContext:managedObjectContext];
}
}
}];
访问该上下文中的对象:
performBlock:
我可能会考虑你的第一个解决方案。
所有这一切,你可以简单地使用“私有队列”上下文作为一个串行队列(只要你按照你需要它们的顺序添加块操作)。
上下文//add this to your CoreDataController
context = [[CoreDataController sharedCoreDataController] serialExecutionBGContext];
[context performBlock:^{ //your block operation code1}];
[context performBlock:^{ //your block operation code2}];
方法将对块进行排队并对其他块进行串行执行,这些块添加了在后台执行的上下文:
{{1}}
这将在后台连续执行code1和code2。
通过这种方式,您可以节省分配新上下文的开销,并可能受益于此上下文完成的缓存。
您可能希望不时地重置此上下文,以便它不会因为获取的对象而变得臃肿。
答案 1 :(得分:0)
对上下文的关注是它只能在一个线程中访问。设置MaxConcurrencyOperationCount并不能保证这一点。另一种方法是将上下文设置为“线程”变量,将上下文存储在每个使用它的线程字典中。
例如:
+ (NSManagedObjectContext*)managedObjectContext
{
NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
NSManagedObjectContext *context = [threadDictionary valueForKey:@"QpyManagedObjectContext"];
if (context == nil) {
@autoreleasepool {
context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[context setStalenessInterval: 10.0];
[context setMergePolicy:[[NSMergePolicy alloc]initWithMergeType:NSOverwriteMergePolicyType]];
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[Qpyd managedObjectModel]];
[context setPersistentStoreCoordinator:coordinator];
NSString *STORE_TYPE = NSSQLiteStoreType;
NSString *path = [[NSProcessInfo processInfo] arguments][0];
path = [path stringByDeletingPathExtension];
NSURL *url = [NSURL fileURLWithPath:[path stringByAppendingPathExtension:@"sqlite"]];
NSError *error;
NSPersistentStore *newStore = [coordinator addPersistentStoreWithType:STORE_TYPE configuration:nil URL:url options:nil error:&error];
if (newStore == nil) {
NSLog(@"Store Configuration Failure %@", ([error localizedDescription] != nil) ? [error localizedDescription] : @"Unknown Error");
}
[threadDictionary setObject:context forKey:@"QpyManagedObjectContext"];
}
}
return context;
}