Core Data 通过GCD实现多线程管理

对于某个比较耗时的数据库操作,我们可以采取多线程的方式,避免阻塞UI线程。本文的完整代码,可以点击这里下载

Core Data的多线程操作,主要涉及两个问题。

1.如何使用多线程?
2.子线程中的更新如何通知主线程?

网上类似的教程非常多,这里就不细说了。主要思路就是,NSManagedObjectContext并不是线程安全的,而NSPersistentStoreCoordinator则是线程安全的。

所以,当我们需要在子线程中,进行CRUD的时候,我们需要新建一个NSManagedObjectContext,同时可以重用此前的NSPersistentStoreCoordinator。因此,NSPersistentStoreCoordinator更像是一个单例类。

在我使用的Xcode 6.3版本里面,勾选上Core Data创建的应用,Core Data的基本代码已经在AppDelegate里面实现了,由于AppDelegate本身就是一个单例类,所以,需要使用NSPersistentStoreCoordinator类对象的时候,直接用AppDelegate的就好了。

关于这两者之间的关系,直接盗用苹果官网的图片,感觉解释得已经非常清楚了。
Core Data 通过GCD实现多线程管理_第1张图片

以下一段代码,演示了如何使用多线程进行CRUD操作。

- (void)viewDidLoad {
    [super viewDidLoad];
    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

    [delegate.managedObjectContext insertTeamWithName:@"Heat"city:@"Miami"];
    [delegate.managedObjectContext insertTeamWithName:@"Lakers"city:@"LA"];
    [delegate.managedObjectContext insertTeamWithName:@"Thunder"city:@"Oklahoma"];
    [delegate saveContext];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSManagedObjectContext *tmpContext = [[NSManagedObjectContext alloc] init];
        [tmpContext setPersistentStoreCoordinator:delegate.persistentStoreCoordinator];

        [tmpContext insertTeamWithName:@"76ers" city:@"Philadelphia"];
        [tmpContext saveContext];

        NSLog(@"%@",[NSThread currentThread]);
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"%@",[NSThread currentThread]);
            self.teamArray = [delegate.managedObjectContext fetchTeamList];
            if (self.teamArray) {
                for (Team *teamObject in self.teamArray) {
                    NSLog(@"Team info : %@, %@\n", teamObject.name, teamObject.city);
                }  
            }
        });
    });
}

需要注意的是,这里的insertTeamWithName方法,在NSManagedObjectContext的extension中被实现。之所以不放在AppDelegate中实现,是因为创建的临时NSManagedObjectContext对象因此也可以调用这些方法,同时面向用户的CRUD操作,仅需要知道NSManagedObjectContext对象即刻,对于底层的实现并不关心。

为了实现主线程和子线程中的数据同步,我们还需要使用一个通知。使得在saveContext的时候,通知主线程中的context更新。
以下这段代码在Appdelegate.m中被实现。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mocDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:nil];

- (void)mocDidSaveNotification:(NSNotification *)notification
{
    NSManagedObjectContext *savedContext = [notification object];

    if (savedContext == self.managedObjectContext) {
        return ;
    }

    if (savedContext.persistentStoreCoordinator != self.persistentStoreCoordinator) {
        return ;
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"Merge changes from other context.\n");
        [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
    });
}

在mocDidSaveNotification方法中,有两个if判断。第一个判断保证自己不会合并自己的更新,第二个判断的作用在于,如果一个App使用了不止一套context时(比如一套context专门负责学生、成绩等业务相关信息。另一个套context负责app本身的信息),一个context不会合并另一套context的信息。

最后的打印结果如下:

2015-06-22 22:31:27.680 MultiThreadCoreData[4369:3916642] 0x7fb13b6117b0>{number = 2, name = (null)}
2015-06-22 22:31:27.722 MultiThreadCoreData[4369:3916522] Merge changes from other context.
2015-06-22 22:31:27.723 MultiThreadCoreData[4369:3916522] 0x7fb13b608220>{number = 1, name = main}
2015-06-22 22:31:27.724 MultiThreadCoreData[4369:3916522] Team info : 76ers, Philadelphia
2015-06-22 22:31:27.724 MultiThreadCoreData[4369:3916522] Team info : Heat, Miami
2015-06-22 22:31:27.724 MultiThreadCoreData[4369:3916522] Team info : Lakers, LA
2015-06-22 22:31:27.724 MultiThreadCoreData[4369:3916522] Team info : Thunder, Oklahoma

可以看到,子线程中被添加的数据,成功的保存,而且主线程的context及时的更新了数据。

你可能感兴趣的:(Core Data 通过GCD实现多线程管理)