Core Data 通過GCD實現多線程管理,coregcd
對於某個比較耗時的資料庫操作,我們可以採取多線程的方式,避免阻塞UI線程。本文的完整代碼,可以點擊這裡下載
Core Data的多線程操作,主要涉及兩個問題。
1.如何使用多線程?
2.子線程中的更新如何通知主線程?
網上類似的教程非常多,這裡就不細說了。主要思路就是,NSManagedObjectContext並不是安全執行緒的,而NSPersistentStoreCoordinator則是安全執行緒的。
所以,當我們需要在子線程中,進行CRUD的時候,我們需要建立一個NSManagedObjectContext,同時可以重用此前的NSPersistentStoreCoordinator。因此,NSPersistentStoreCoordinator更像是一個單例類。
在我使用的Xcode 6.3版本裡面,勾選上Core Data建立的應用,Core Data的基本代碼已經在AppDelegate裡面實現了,由於AppDelegate本身就是一個單例類,所以,需要使用NSPersistentStoreCoordinator類對象的時候,直接用AppDelegate的就好了。
關於這兩者之間的關係,直接盜用蘋果官網的圖片,感覺解釋得已經非常清楚了。
以下一段代碼,示範了如何使用多線程進行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] <NSThread: 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] <NSThread: 0x7fb13b608220>{number = 1, name = main}2015-06-22 22:31:27.724 MultiThreadCoreData[4369:3916522] Team info : 76ers, Philadelphia2015-06-22 22:31:27.724 MultiThreadCoreData[4369:3916522] Team info : Heat, Miami2015-06-22 22:31:27.724 MultiThreadCoreData[4369:3916522] Team info : Lakers, LA2015-06-22 22:31:27.724 MultiThreadCoreData[4369:3916522] Team info : Thunder, Oklahoma
可以看到,子線程中被添加的資料,成功的儲存,而且主線程的context及時的更新了資料。