zz 說說iOS的多線程Core Data

來源:互聯網
上載者:User

標籤:http   os   io   使用   ar   for   資料   div   cti   

Core Data是iOS中很重要的一個部分,可以理解為基於SQLite(當然也可以是其他的Storage,如In-memory,只是SQLite比較常見)的一個ORM實現,所以有關聯式資料庫的特性,又不用寫SQL。順便吐一下槽,官方說法是使用Core Data能減少50%-70%的代碼量,但相信用過的人應該都心裡明白,Core Data使用起來還是比較麻煩的,這也是為什麼有不少的第三方類庫來代替/二次封裝Core Data。

稍微複雜的應用就有可能出現同時處理多份資料的情況,這就需要用到多線程Core Data。在 iOS 5之前,官方推薦的是使用「Thread Confinement」,就是每個線程使用獨立的MOC(managed object context),然後共用一個PSC(persistent store coordinator)。同時線上程之間傳遞資料時,要傳遞objectID,而不是object,因為前者是安全執行緒的,後者不是。

如果A線程裡,對PSC執行了CUD(create, update, delete)操作,其他線程如何感知呢?這就需要通過監聽事件來實現。比如線上程A中監聽「NSManagedObjectContextDidSaveNotification」事件,如果線程B中執行了CUD操作,線程A就能感知到,並觸發響應的action,雖然可以通過noti userinfo來擷取managed objects,但因為它們是關聯到另一個MOC,所以無法直接操作它們,解決方案就是調用「mergeChangesFromContextDidSaveNotification:」方法。

用一張圖來形容的話,大體就是這樣:

- (void)_setupCoreDataStack{     // setup managed object model     NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Database" withExtension:@"momd"];     _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];      // setup persistent store coordinator     NSURL *storeURL = [NSURL fileURLWithPath:[[NSString cachesPath] stringByAppendingPathComponent:@"Database.db"]];      NSError *error = nil;     _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_managedObjectModel];      if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {         // handle error   }      // create MOC     _managedObjectContext = [[NSManagedObjectContext alloc] init];     [_managedObjectContext setPersistentStoreCoordinator:_persistentStoreCoordinator];      // subscribe to change notifications     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_mocDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:nil];}

再來看看Notification Handler,主要作用就是合并新的變化。

- (void)_mocDidSaveNotification:(NSNotification *)notification{     NSManagedObjectContext *savedContext = [notification object];      // ignore change notifications for the main MOC     if (_managedObjectContext == savedContext) {          return;     }      dispatch_sync(dispatch_get_main_queue(), ^{      [_managedObjectContext mergeChangesFromContextDidSaveNotification:notification];     });}

這種方式實現起來和維護起來都有點麻煩,所以iOS 5中就出現了更加方便和靈活的實現,也就是「Nested MOC」。

[[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

可以看到在初始化時可以選擇ConcurrencyType,可選的有3個:

NSConfinementConcurrencyType

這個是預設項,每個線程一個獨立的Context,主要是為了相容之前的設計。

NSPrivateQueueConcurrencyType

建立一個private queue(使用GCD),這樣就不會阻塞主線程。

NSMainQueueConcurrencyType

建立一個main queue,使用主線程,會阻塞。

還有一個重要的變化是MOC可以指定parent。有了parent後,CUD操作會冒泡到parent。一個parent可以有多個child。parent還可以有parent。

因為UI相關的資料必須在主線程擷取,同時又要避免資料庫的I/O操作阻塞主線程,所以就有了下面這個模型:

我對這種實現方式的一個困惑是:child無法得知parent的變化,也就是說,如果NSFetchedResultsController綁定了Main MOC,當Background Write MOC save時,NSFetchedResultsController為何能知曉?求指點。

這種方式比「Thread Confinement」稍微簡單了點,也更明了。不過個人還是推薦使用MagicalRecord,因為實現起來更加簡單,等有空再寫一篇。

寫了一個使用了這個模型的demo,配合TableView和NSFetchedResultsController,有興趣的可以看下:https://github.com/limboy/coredata-with-tableview

2013/06/17更新

之前的困惑已消除,NSFetchedResultsController跟PSC無關,只要綁定的MOC有了save動作,NSFetchedResultsController就會收到通知,無論這個save操作有沒有寫入到持久層。

zz 說說iOS的多線程Core Data

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.