親子関係を持つNSManagedObjectContextの保存時の動作

# はじめに

http://www.cocoanetics.com/2012/07/multi-context-coredata/
のAsynchronous Saving等で言及されている。

Core Dataの３段階コンテキスト設計

バックグランドで書き込みを行うNSManagedObjectContext
↓
メインスレッドのNSManagedObjectContext
↓
バッググランドでデーターベースに保存するNSManagedObjectContext
↓
NSPersistentStoreCoordinatorの親子関係を持つNSManagedObjectContextのチェーンについて
どのように通知が行われるの今一疑問でした。
そこで、以下のコードを作成してどう動くか実験してみました。

# 検証コード

```objc:
    // 各NSManagedObjectContextのポインター値を出力
    NSLog(@"backgroundManagedObjectContext=%@",
          [NSManagedObjectContext backgroundManagedObjectContext]);
    NSLog(@"mainManagedObjectContext=%@",
          [NSManagedObjectContext mainManagedObjectContext]);
    NSLog(@"persistenceManagedObjectContext=%@",
          [NSManagedObjectContext persistenceManagedObjectContext]);
    
    // NSManagedObjectContextが発行する通知を登録
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center addObserverForName:NSManagedObjectContextObjectsDidChangeNotification
                        object:nil
                         queue:[NSOperationQueue mainQueue]
                    usingBlock:^(NSNotification *notification) {
                        NSLog(@"NSManagedObjectContextObjectsDidChangeNotification "
                              @"NSManagedObjectContext=%@", notification.object);
                    }];
    [center addObserverForName:NSManagedObjectContextDidSaveNotification
                        object:nil
                         queue:[NSOperationQueue mainQueue]
                    usingBlock:^(NSNotification *notification) {
                        NSLog(@"NSManagedObjectContextDidSaveNotification "
                              @"NSManagedObjectContext=%@", notification.object);
                    }];
    
    NSManagedObjectContext *backgroundMOC = [NSManagedObjectContext backgroundManagedObjectContext];
    [backgroundMOC performBlockAndWait:^() {
        
        [NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:backgroundMOC];
        [backgroundMOC save:nil];
        
        NSLog(@"Saved object in backgroundMOC");
        
        NSManagedObjectContext *mainMOC = [NSManagedObjectContext mainManagedObjectContext];
        [mainMOC performBlockAndWait:^() {
            [mainMOC save:nil];
            
            NSLog(@"Saved object in mainMOC");
            
            NSManagedObjectContext *persistenceMOC = [NSManagedObjectContext persistenceManagedObjectContext];
            [persistenceMOC performBlockAndWait:^() {
                [persistenceMOC save:nil];
                
                NSLog(@"Saved object in persistenceMOC");
                
            }];
        }];
    }];
```

# 実行結果

実行結果です。スタック上側(子側)のコンテキストからはあたかもNSPerstenceStoreに保存しているように見えるのは当たり前と言えば当たり前ですが、下側(親側)で子からsave:メソッドを呼ばれた瞬間に変更通知が飛んで来ています。

```
2014-08-17 23:54:48.762 MultiThreadCoreData[1832:569037] backgroundManagedObjectContext=<NSManagedObjectContext: 0x7ff368434be0>
2014-08-17 23:54:48.763 MultiThreadCoreData[1832:569037] mainManagedObjectContext=<NSManagedObjectContext: 0x7ff368435e60>
2014-08-17 23:54:48.763 MultiThreadCoreData[1832:569037] persistenceManagedObjectContext=<NSManagedObjectContext: 0x7ff3684365a0>
2014-08-17 23:54:48.763 MultiThreadCoreData[1832:569037]

NSManagedObjectContextObjectsDidChangeNotification NSManagedObjectContext=<NSManagedObjectContext: 0x7ff368434be0>
2014-08-17 23:54:48.764 MultiThreadCoreData[1832:569037] NSManagedObjectContextObjectsDidChangeNotification NSManagedObjectContext=<NSManagedObjectContext: 0x7ff368435e60>
2014-08-17 23:54:48.764 MultiThreadCoreData[1832:569037] NSManagedObjectContextDidSaveNotification NSManagedObjectContext=<NSManagedObjectContext: 0x7ff368434be0>
2014-08-17 23:54:48.764 MultiThreadCoreData[1832:569037] Saved object in backgroundMoc

2014-08-17 23:54:48.765 MultiThreadCoreData[1832:569037] NSManagedObjectContextObjectsDidChangeNotification NSManagedObjectContext=<NSManagedObjectContext: 0x7ff3684365a0>
2014-08-17 23:54:48.765 MultiThreadCoreData[1832:569037] NSManagedObjectContextDidSaveNotification NSManagedObjectContext=<NSManagedObjectContext: 0x7ff368435e60>
2014-08-17 23:54:48.765 MultiThreadCoreData[1832:569037] Saved object in mainMoc

2014-08-17 23:54:48.767 MultiThreadCoreData[1832:569037] NSManagedObjectContextDidSaveNotification NSManagedObjectContext=<NSManagedObjectContext: 0x7ff3684365a0>
2014-08-17 23:54:48.782 MultiThreadCoreData[1832:569037] Saved object in persistenceMoc
```

# まとめ

やや強引ですがとりあえず纏めます。

・変更内容を下側のコンテキストにプッシュする際、スタック上側(子側)のコンテキストからはあたかもNSPerstenceStoreに保存するような動作をする。
・スタック下側(親側)のコンテキストからは、上側(子側)のコンテキストからのプッシュは一括編集が行われたかの用に見える(NSManagedObjectContextObjectsDidChangeNotificationが通知される)。