在串行NSOperationQueue上初始化NSManagedObjectContext

时间:2014-01-05 19:55:41

标签: core-data nsmanagedobjectcontext nsoperation nsoperationqueue

我有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做什么是线程安全的,通常被认为是正常的?我将非常感谢一些澄清和/或表明我应该采取不同的做法。如果您需要查看更多代码,请询问。

提前致谢。

2 个答案:

答案 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;
}