CoreData +多线程模式。我做对了吗?

时间:2013-07-13 13:58:06

标签: ios objective-c design-patterns core-data

我编写了一个使用Core Data存储其内容的iOS应用程序。数据存储在托管对象中并在单独的线程中更新(我正在使用GCD)。 Apple在其Core Data Programming Guide模式中建议采用两种方式来采用Core Data在多线程环境中使用:

  1. 为每个线程创建单独的托管对象上下文,并共享一个持久性存储协调器。 这是通常推荐的方法。
  2. 为每个线程创建单独的托管对象上下文和持久性存储协调器。 这种方法以更高的复杂性为代价提供更高的并发性(特别是如果您需要在不同的上下文之间进行通信)并增加内存使用量。
  3. 所以我选择了第一个。 我有一个Database类来管理所有与Core Data相关的东西。

    // Database.h
    
    #import <CoreData/CoreData.h>
    
    @interface Database : NSObject
    
    @property (nonatomic, retain, readonly) NSManagedObjectModel *model;
    @property (nonatomic, retain, readonly) NSManagedObjectContext *context;
    @property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *coordinator;
    
    + (Database *)sharedInstance;
    
    @end
    
    
    // Database.m
    
    #import "Database.h"
    
    static NSManagedObjectModel *sharedModel;
    static NSPersistentStoreCoordinator *sharedCoordinator;
    
    static NSMutableDictionary *contexts;
    
    @implementation Database
    
    + (NSMutableDictionary *)contextsDictionary
    {
        if (!contexts) {
            contexts = [[NSMutableDictionary alloc] init];
        }
        return contexts;
    }
    
    + (NSManagedObjectContext *)contextForThread:(NSThread *)thread
    {
        id threadKey = @(thread.hash);
        NSManagedObjectContext *context = [Database contextsDictionary][threadKey];
        if (!context) {
            context = [[NSManagedObjectContext alloc] init];
            context.persistentStoreCoordinator = sharedCoordinator;
            contexts[threadKey] = context;
            [context release];
            [[NSNotificationCenter defaultCenter] addObserver:[Database class]
                                                     selector:@selector(threadWillExit:)
                                                         name:NSThreadWillExitNotification
                                                       object:thread];
        }
        return context;
    }
    
    + (void)threadWillExit:(NSThread *)thread
    {
        id threadKey = @(thread.hash);
        [contexts removeObjectForKey:threadKey];
        [[NSNotificationCenter defaultCenter] removeObserver:[Database class]
                                                        name:NSThreadWillExitNotification
                                                      object:thread];
    }
    
    + (Database *)sharedInstance
    {
        static Database *shared;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            shared = [[Database alloc] init];
        });
        return shared;
    }
    
    - (id)init
    {
        self = [super init];
        if (self) {
            sharedModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
            sharedCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:sharedModel];
    
            NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
            NSURL *storeUrl = [NSURL fileURLWithPath:[docsDir stringByAppendingPathComponent: @"MyModelFile"]];
            NSError *error = nil;
            [sharedCoordinator addPersistentStoreWithType:NSBinaryStoreType
                                            configuration:nil
                                                      URL:storeUrl
                                                  options:nil
                                                    error:&error];
            NSAssert(!error, @"Initialization error %@", error);
        }
        return self;
    }
    
    - (NSManagedObjectModel *)model
    {
        return sharedModel;
    }
    
    - (NSPersistentStoreCoordinator *)coordinator
    {
        return sharedCoordinator;
    }
    
    - (NSManagedObjectContext *)context
    {
        return [Database contextForThread:[NSThread currentThread]];
    }
    
    - (void)dealloc
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
        [sharedModel release];
        [sharedCoordinator release];
        [contexts release];
    
        [super dealloc];
    }
    @end
    

    所以我很好奇,我做得对吗?我的代码有问题吗?我可以在这里使用任何模式吗?

    感谢。

1 个答案:

答案 0 :(得分:0)

所描述的多线程模式现在不相关,因为核心数据具有内置并发支持。如文章Core Data Release Notes for OS X v10.7 and iOS 5.0Common Background Practices中所述,可以使用NSPrivateQueueConcurrencyTypeNSMainQueueConcurrencyType配置适当的并发类型的moc。然后,可以在传递给performBlockperformBlockAndWait方法的块中执行具有托管对象上下文的每个操作,并让核心数据内部处理所有并发内容。