CoreData 从入门到精通(四)并发操作
通常情況下,CoreData 的增刪改查操作都在主線程上執(zhí)行,那么對數(shù)據(jù)庫的操作就會影響到 UI 操作,這在操作的數(shù)據(jù)量比較小的時候,執(zhí)行的速度很快,我們也不會察覺到對 UI 的影響,但是當數(shù)據(jù)量特別大的時候,再把 CoreData 的操作放到主線程中就會影響到 UI 的流暢性。自然而然地我們就會想到使用后臺線程來處理大量的數(shù)據(jù)操作。
使用后臺 managedObjectContext
CoreData 里使用后臺更新數(shù)據(jù)最常用的方案是一個 persistentStoreCoordinator 持久化存儲協(xié)調(diào)器對應兩個 managedObjectContext 管理上下文,NSManagedObjectContext 在創(chuàng)建時,可以傳入 ConcurrencyType 來指定 context 的并發(fā)類型。指定 NSMainQueueConcurrencyType 就是我們平時創(chuàng)建的運行在主隊列的 context;指定成 NSPrivateQueueConcurrencyType 的話,context 就會運行在它所管理的一個私有隊列中;另外還有 NSConfinementConcurrencyType 是適用于舊設備的并發(fā)類型,現(xiàn)在已經(jīng)被廢棄了,所以實際上只有兩種并發(fā)類型。
下面是創(chuàng)建 backgroundContext 的代碼:
在最新的 iOS 10 中,CoreData 棧的創(chuàng)建被封裝在了 NSPersistentContainer 類中,用它來創(chuàng)建 backgroundContext 更加簡單:
NSManagedObjectContext *backgroundContext = ((AppDelegate *)[UIApplication sharedApplication].delegate).persistentContainer.newBackgroundContext;另外,后臺 context 的操作得放在 performBlock 或 performBlockAndWait 方法里執(zhí)行,performBlock 會異步的執(zhí)行,不會阻塞當前的線程,而 performBlockAndWait 則會阻塞當前的線程直到方法返回才會繼續(xù)向下執(zhí)行。下面是一段后臺插入數(shù)據(jù)的示例代碼:
[self.backgroundContext performBlock:^{for (NSUInteger i = 0; i < 100000; i++) {NSString *name = [NSString stringWithFormat:@"student-%d", arc4random_uniform(9999)]; int16_t age = arc4random_uniform(10) + 10; int16_t stuId = arc4random_uniform(9999); Student *student = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.backgroundContext]; student.studentName = name; student.studentAge = age; student.studentId = stuId; } NSError *error; [self.backgroundContext save:&error]; [self.logger dealWithError:error whenFail:@"failed to insert" whenSuccess:@"insert success"]; }];后臺插入數(shù)據(jù)之后,還沒有完,因為數(shù)據(jù)是通過后臺的 context 寫入到本地的持久化數(shù)據(jù)庫的,所以這時候主隊列的 context 是不知道本地數(shù)據(jù)變化的,所以還需要通知到主隊列的 context:“數(shù)據(jù)庫的內(nèi)容有變化啦,看看你有沒有需要合并的”。這個過程可以通過監(jiān)聽一條通知來實現(xiàn)。這個通知就是 NSManagedObjectContextDidSaveNotification,在每次調(diào)用 NSManagedObjectContext 的 save:方法時都會自動發(fā)送,通知中的 userInfo 中包含了修改的數(shù)據(jù),可以通過 NSInsertedObjectsKey、NSUpdatedObjectsKey、 NSDeletedObjectsKey 這三個 key 獲取到。
NSManagedObjectContextDidSaveNotification-w600
收到通知之后,只需要調(diào)用 [self.mainContext mergeChangesFromContextDidSaveNotification:note] 就可以將修改的數(shù)據(jù)合并到主線程的 context。
下面是示例代碼:
- (void)viewDidLoad {[super viewDidLoad];[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveContextSave:) name:NSManagedObjectContextDidSaveNotification object:self.backgroundContext]; } - (void)doSometingInsertingInBackground { // backgroundContext .... } - (void)receiveContextSave:(NSNotification *)note { [self.context mergeChangesFromContextDidSaveNotification:note]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; }注意:通知的 userInfo 里保存的 managedObjects 不可以直接在另一個線程的 context 中直接使用!也就是 managedObject 不是跨線程的,如果想要在別的線程操作,必須通過 objectId 在另一個 context 里再重新獲得這個 object。
- (void)receiveContextSave:(NSNotification *)note {[self.context mergeChangesFromContextDidSaveNotification:note];NSSet<Student *> *managedObjects = note.userInfo[NSInsertedObjectsKey]; NSManagedObjectID *studentId = managedObjects.allObjects[0].objectID; [self.context performBlock:^{ // 這是錯的 // Student *wrongStudent = managedObjects.allObjects[0]; // 應該這么做 Student *student = [self.context objectWithID:studentId]; // modify student... }]; }轉(zhuǎn)載于:https://www.cnblogs.com/Free-Thinker/p/7059726.html
總結(jié)
以上是生活随笔為你收集整理的CoreData 从入门到精通(四)并发操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java中main函数的String[]
- 下一篇: Python开发【第一篇】:目录