永島 次朗 / Jiro Nagashima


Twitter
@hedjirog


nana music, inc. / iOS Engineer
http://nana-music.com
Goal




UI操作を妨害することなく
高度なデータ処理をしたい
Goal
         UI操作を妨害することなく
         高度なデータ処理をしたい



                     解決策



•   CoreDataをマルチスレッドで扱う手法が有効

    •   複数のContext

    •   parentContext(iOS5 以上)

    •   performBlock: メソッド(iOS5 以上)
Agenda

• CoreDataフレームワークの概要
• CoreDataとマルチスレッド
 • 単一/複数Contextによる設計
 • CoreDataの便利機能
  • parentContext(iOS5 以上)
  • performBlock: メソッド(iOS5 以上)
CoreDataフレームワークの概要
Demo
CoreDataフレームワークの概要

• 4つのクラスとクラス間の関係
 ManagedObject

 ManagedObject

 ManagedObject

    ManagedObjectContext               PersistentStoreCoordinator




                           FetchedResultsController
CoreDataフレームワークの概要


 ManagedObject




• データを表わすオブジェクト
CoreDataフレームワークの概要

 ManagedObject

 ManagedObject

 ManagedObject

    ManagedObjectContext




• オブジェクトの集合を管理
• オブジェクトの挿入/更新/削除
CoreDataフレームワークの概要

 ManagedObject

 ManagedObject

 ManagedObject                         PersistentStore

    ManagedObjectContext   PersistentStoreCoordinator




• オブジェクトの永続化
• 永続ストアへマッピング
CoreDataフレームワークの概要

 ManagedObject

 ManagedObject

 ManagedObject

    ManagedObjectContext               PersistentStoreCoordinator




                                         TableView
                           FetchedResultsController



• オブジェクトの変更を監視
• TableViewの表示と整合性を保つ
CoreDataとマルチスレッド
単一Contextによる設計
• 新規オブジェクト追加時
     ManagedObject




        ManagedObjectContext                       PersistentStoreCoordinator




                                                           通知のタイミング
                                                           1. 空のオブジェクト追加時
                               FetchedResultsController    2. オブジェクト更新時
    問題点


•   過剰な通知

    •   オブジェクトの更新後のみ通知したい
単一Contextによる設計
  • オブジェクト永続化時
                                 2. 永続化の
       ManagedObject            所要時間が増加



         ManagedObjectContext                       PersistentStoreCoordinator



1. 負荷の高い更新処理



                                FetchedResultsController
      問題点


  •   永続化に処理時間を要するとUI操作を妨害
単一Contextによる設計

•   過度な通知が発生する可能性

•   永続化時に処理時間を要してUIを妨害する可能性




         複数のContextを作成
複数Contextによる設計
Main Thread


        ManagedObject


          ManagedObjectContext
                                                     PersistentStoreCoordinator




Background

                                 FetchedResultsController
        ManagedObject


          ManagedObjectContext



•   スレッド毎にContextを作成

    •    メインスレッド:監視対象、永続化向け

    •    バックグラウンド:(オブジェクトの)更新向け
複数Contextによる設計
     Main Thread


            ManagedObject


              ManagedObjectContext
                                                         PersistentStoreCoordinator

オブジェクト更新後にマージ

     Background

                                                                適切なタイミングで通知
                                     FetchedResultsController
            ManagedObject


              ManagedObjectContext



    •   適切なタイミングで通知が可能

    •   Context(スレッド)毎に役割分担

        •    処理負荷の分散
CoreDataの便利機能


• parentContext(iOS5 以上)
 • Context間での更新内容のマージが容易に
• performBlock: メソッド(iOS5 以上)
 • 非同期処理の記述が容易に
parentContext
Main Thread




          ManagedObjectContext

                        親Context                       PersistentStoreCoordinator

        Parent



                        子Context
Background                         FetchedResultsController




          ManagedObjectContext



•   複数のContext間で親子関係を定義できる

    •    setParentContext: メソッドで親Contextを指定
parentContext
      Main Thread




               ManagedObjectContext

                             親Context                       PersistentStoreCoordinator

             Parent


オブジェクト更新後にマージ
                             子Context
      Background                        FetchedResultsController




               ManagedObjectContext



     •   Context間での更新内容のマージが容易に

         •    子Contextのsave: メソッド呼び出しでマージ
parentContext
• 親Contextの作成
  Main Thread




          ManagedObjectContext

                        親Context
                                      Contextの更新処理を行なうスレッドが決定

 NSMangedObjectContext *parentContext;
 parentContext = [[NSManagedObjectContext alloc]
                   initWithConcurrencyType:NSMainQueueConcurrencyType];

 [parentContext setPersistentStoreCoordinator:_persistentStoreCoordinator];
parentContext
• 子Contextの作成
  Main Thread                                    Background
                                   Parent




          ManagedObjectContext                            ManagedObjectContext

                        親Context                                        子Context
                                        Contextの更新処理を行なうスレッドが決定

 NSMangedObjectContext *childContext;
 childContex = [[NSManagedObjectContext alloc]
                initWithConcurrencyType:NSPrivateQueueConcurrencyType];

 [childContext setParentContext:parentContext];

                                            親Contextの指定
performBlock:
•   非同期処理の記述が容易に
 Main Thread                               Background
                                  Parent




         ManagedObjectContext                     ManagedObjectContext

                       親Context                                 子Context

[childContext performBlock:^{       非同期で処理が実行される
    // push to parent
    NSError *error;
    if (![childContext save:&error]) {
        // handle error
    }
 
    [parentContext performBlock:^{        非同期で処理が実行される
        NSError *error;
        if (![parentContext save:&error]) {
            // handle error
        }
    }];
}];
performBlock:
•   parentContextとの組み合わせ
 Main Thread                                   Background
                                  Parent




         ManagedObjectContext                         ManagedObjectContext

                       親Context                                     子Context

[childContext performBlock:^{
    // push to parent
    NSError *error;
    if (![childContext save:&error]) {
        // handle error
    }
                                              親Contextへ変更内容をマージ
 
    [parentContext performBlock:^{
        NSError *error;
        if (![parentContext save:&error]) {
            // handle error
        }
    }];
}];
performBlock:
•   parentContextとの組み合わせ
 Main Thread                                  Background
                                  Parent




         ManagedObjectContext                        ManagedObjectContext

                       親Context                                    子Context

[childContext performBlock:^{
    // push to parent
    NSError *error;
    if (![childContext save:&error]) {
        // handle error
    }
 
    [parentContext performBlock:^{
        NSError *error;
        if (![parentContext save:&error]) {
            // handle error
        }
                                              親Contextの永続化
    }];
}];
まとめ

• UI操作を妨害しない高度なデータ処理
• CoreDataをマルチスレッドで利用する
 • 複数のContextを用意
 • parentContext で親子関係を定義
 • performBlock: メソッドで非同期処理
参考資料


• Multi-Context CoreData
 http://www.cocoanetics.com/2012/07/multi-context-coredata/
より詳しい情報


•   WWDC 2011
    •   Session 303 - What's New in Core Data on iOS

    •   Session 315 - What's New in Core Data on Mac OS X


•   WWDC 2012
    •   Session 214 - Core Data Best Practices

CoreData 非同期データ処理

  • 2.
    永島 次朗 /Jiro Nagashima Twitter @hedjirog nana music, inc. / iOS Engineer http://nana-music.com
  • 3.
  • 4.
    Goal UI操作を妨害することなく 高度なデータ処理をしたい 解決策 • CoreDataをマルチスレッドで扱う手法が有効 • 複数のContext • parentContext(iOS5 以上) • performBlock: メソッド(iOS5 以上)
  • 5.
    Agenda • CoreDataフレームワークの概要 • CoreDataとマルチスレッド • 単一/複数Contextによる設計 • CoreDataの便利機能 • parentContext(iOS5 以上) • performBlock: メソッド(iOS5 以上)
  • 6.
  • 7.
  • 8.
    CoreDataフレームワークの概要 • 4つのクラスとクラス間の関係 ManagedObject ManagedObject ManagedObject ManagedObjectContext PersistentStoreCoordinator FetchedResultsController
  • 9.
  • 10.
    CoreDataフレームワークの概要 ManagedObject ManagedObject ManagedObject ManagedObjectContext • オブジェクトの集合を管理 • オブジェクトの挿入/更新/削除
  • 11.
    CoreDataフレームワークの概要 ManagedObject ManagedObject ManagedObject PersistentStore ManagedObjectContext PersistentStoreCoordinator • オブジェクトの永続化 • 永続ストアへマッピング
  • 12.
    CoreDataフレームワークの概要 ManagedObject ManagedObject ManagedObject ManagedObjectContext PersistentStoreCoordinator TableView FetchedResultsController • オブジェクトの変更を監視 • TableViewの表示と整合性を保つ
  • 13.
  • 14.
    単一Contextによる設計 • 新規オブジェクト追加時 ManagedObject ManagedObjectContext PersistentStoreCoordinator 通知のタイミング 1. 空のオブジェクト追加時 FetchedResultsController 2. オブジェクト更新時 問題点 • 過剰な通知 • オブジェクトの更新後のみ通知したい
  • 15.
    単一Contextによる設計 •オブジェクト永続化時 2. 永続化の ManagedObject 所要時間が増加 ManagedObjectContext PersistentStoreCoordinator 1. 負荷の高い更新処理 FetchedResultsController 問題点 • 永続化に処理時間を要するとUI操作を妨害
  • 16.
    単一Contextによる設計 • 過度な通知が発生する可能性 • 永続化時に処理時間を要してUIを妨害する可能性 複数のContextを作成
  • 17.
    複数Contextによる設計 Main Thread ManagedObject ManagedObjectContext PersistentStoreCoordinator Background FetchedResultsController ManagedObject ManagedObjectContext • スレッド毎にContextを作成 • メインスレッド:監視対象、永続化向け • バックグラウンド:(オブジェクトの)更新向け
  • 18.
    複数Contextによる設計 Main Thread ManagedObject ManagedObjectContext PersistentStoreCoordinator オブジェクト更新後にマージ Background 適切なタイミングで通知 FetchedResultsController ManagedObject ManagedObjectContext • 適切なタイミングで通知が可能 • Context(スレッド)毎に役割分担 • 処理負荷の分散
  • 19.
    CoreDataの便利機能 • parentContext(iOS5 以上) • Context間での更新内容のマージが容易に • performBlock: メソッド(iOS5 以上) • 非同期処理の記述が容易に
  • 20.
    parentContext Main Thread ManagedObjectContext 親Context PersistentStoreCoordinator Parent 子Context Background FetchedResultsController ManagedObjectContext • 複数のContext間で親子関係を定義できる • setParentContext: メソッドで親Contextを指定
  • 21.
    parentContext Main Thread ManagedObjectContext 親Context PersistentStoreCoordinator Parent オブジェクト更新後にマージ 子Context Background FetchedResultsController ManagedObjectContext • Context間での更新内容のマージが容易に • 子Contextのsave: メソッド呼び出しでマージ
  • 22.
    parentContext • 親Contextの作成 Main Thread ManagedObjectContext 親Context Contextの更新処理を行なうスレッドが決定 NSMangedObjectContext *parentContext; parentContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; [parentContext setPersistentStoreCoordinator:_persistentStoreCoordinator];
  • 23.
    parentContext • 子Contextの作成 Main Thread Background Parent ManagedObjectContext ManagedObjectContext 親Context 子Context Contextの更新処理を行なうスレッドが決定 NSMangedObjectContext *childContext; childContex = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [childContext setParentContext:parentContext]; 親Contextの指定
  • 24.
    performBlock: • 非同期処理の記述が容易に Main Thread Background Parent ManagedObjectContext ManagedObjectContext 親Context 子Context [childContext performBlock:^{ 非同期で処理が実行される // push to parent NSError *error; if (![childContext save:&error]) { // handle error }   [parentContext performBlock:^{ 非同期で処理が実行される NSError *error; if (![parentContext save:&error]) { // handle error } }]; }];
  • 25.
    performBlock: • parentContextとの組み合わせ Main Thread Background Parent ManagedObjectContext ManagedObjectContext 親Context 子Context [childContext performBlock:^{ // push to parent NSError *error; if (![childContext save:&error]) { // handle error } 親Contextへ変更内容をマージ   [parentContext performBlock:^{ NSError *error; if (![parentContext save:&error]) { // handle error } }]; }];
  • 26.
    performBlock: • parentContextとの組み合わせ Main Thread Background Parent ManagedObjectContext ManagedObjectContext 親Context 子Context [childContext performBlock:^{ // push to parent NSError *error; if (![childContext save:&error]) { // handle error }   [parentContext performBlock:^{ NSError *error; if (![parentContext save:&error]) { // handle error } 親Contextの永続化 }]; }];
  • 27.
    まとめ • UI操作を妨害しない高度なデータ処理 • CoreDataをマルチスレッドで利用する • 複数のContextを用意 • parentContext で親子関係を定義 • performBlock: メソッドで非同期処理
  • 28.
    参考資料 • Multi-Context CoreData http://www.cocoanetics.com/2012/07/multi-context-coredata/
  • 29.
    より詳しい情報 • WWDC 2011 • Session 303 - What's New in Core Data on iOS • Session 315 - What's New in Core Data on Mac OS X • WWDC 2012 • Session 214 - Core Data Best Practices