パースしたXMLをCoreDataに登録する際にハマったこと

# iOSでwebAPIのXMLデータをパースし、CoreDataに変換

アプリの開発依頼を受けて、web上から飛んでくるAPIを取得し
CoreDataに格納する際にハマったことをメモしておきます。

## 前提条件
NSHttpRequest等を使用し、XMLデータを取得してパースが済んでいる状態とします。

## エンティティー構造
* カテゴリー
* 記事

この２つのエンティティを作成し、表示したい内容をプロパティとして設定。
カテゴリー - 記事は 1対多の関係で作成。

## やろうとしたこと
カテゴリーごとに記事を分けて表示する機能要件があったので、
パース済みのXMLをジャンル毎にNSMutableDictionary型（キー値：カテゴリー名　値：カテゴリー毎の記事のNSSet型に格納したもの）に格納し、カテゴリーエンティティの記事に登録する。

処理は記事一覧のFetchedResultControllerが存在するViewControllerクラスにて行う。

## ハマったこと
既に記事エンティティのFetchedResultControllerが存在しているが、記事データに紐づけるためのカテゴリーManagedObjectを特定できない。

## 試み : NSFetchedResultControllerをもう１つ呼び出す
tableViewDelegateの:cellForAtIndexPathにてfetchedResultControllerをindexPath毎に呼び出しているので、カテゴリー用のFetchedResultControllerを呼び出せばいいのではないのか？
という安易な考えでもう一つ呼び出し、実装してみた！

NSPredicateにてカテゴリー名を指定して絞り込みをかける。

```objc
- (NSFetchedResultsController *)insertPostDataInGenre:(NSString *)genreName{
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    [fetchRequest setFetchBatchSize:20];
    ;
    NSString *predicateCondition = [NSString stringWithFormat:@"name CONTAINS '%@'",genreName];
    fetchRequest.predicate = [NSPredicate predicateWithFormat:predicateCondition];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
    NSArray *sortDescriptors = @[sortDescriptor];
    
    [fetchRequest setSortDescriptors:sortDescriptors];
    
	NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    
	NSError *error = nil;
	if (![self.fetchedResultsController performFetch:&error]) {useful during development. 
	    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
	    abort();
	}
    
    return fetchedResultsController;
}
```

データ保存部分

```objc
- (void)parserDidEndDocument:(NSXMLParser *)parser{
    
    for (NSMutableString *c_name in _Entries) {
        if(c_name != nil){
            NSFetchedResultsController *fetchedResultController = [self insertPostDataInGenre:c_name];
            Category *category = [[fetchedResultController section] objectAtIndex:0]
            [category addPost:_Entries[c_name]];
        }
        
        NSError *error;
        
        if(![self.managedObjectContext save:&error]){
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
        
    }    
}
```

CategoryのManagedObjectが返ってくることは無かった・・・orz


## [NSManagementObjectContext executeFetchRequest:]との出会い

NSManagementObjectContextのメンバ関数

**executeFetchRequest関数**

この関数の戻り値はNSArray型で設定されたNSFetchRequest型を投げることによって結果を返してくれる関数なのですが・・・・

なんと、こいつフェッチした結果のNSManagementObject型を格納してやがったのです！

## コードの修正

格納したいジャンルのManagementObjectを取得

```objc
- (Category *)insertPostDataInCategory:(NSString *)categoryName{
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];
    
    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];
    ;
    NSString *predicateCondition = [NSString stringWithFormat:@"name CONTAINS '%@'",categoryName];
    fetchRequest.predicate = [NSPredicate predicateWithFormat:predicateCondition];
    
    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
    NSArray *sortDescriptors = @[sortDescriptor];
    
    [fetchRequest setSortDescriptors:sortDescriptors];
    
	NSError *error = nil;
    
    NSArray *array = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
    
    return [array objectAtIndex:0];
}
```

保存部分

```objc

- (void)parserDidEndDocument:(NSXMLParser *)parser{
    
    for (NSMutableString *c_name in _Entries) {
        if(c_name != nil){
            // 
            Category *category = [self insertPostDataInCategory:c_name];
            
            [category addPost:_Entries[c_name]];
        }
        
        // データの保存
        NSError *error;
        if(![self.managedObjectContext save:&error]){
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
        
    }    
}

```

これで期待通りにカテゴリーに紐づいた記事をCoreDataに無事登録することができた。

メモ書き程度なので雑なのは勘弁してくださいm(_ _)m