iOSでwebAPIのXMLデータをパースし、CoreDataに変換
アプリの開発依頼を受けて、web上から飛んでくるAPIを取得し
CoreDataに格納する際にハマったことをメモしておきます。
前提条件
NSHttpRequest等を使用し、XMLデータを取得してパースが済んでいる状態とします。
エンティティー構造
- カテゴリー
- 記事
この2つのエンティティを作成し、表示したい内容をプロパティとして設定。
カテゴリー - 記事は 1対多の関係で作成。
やろうとしたこと
カテゴリーごとに記事を分けて表示する機能要件があったので、
パース済みのXMLをジャンル毎にNSMutableDictionary型(キー値:カテゴリー名 値:カテゴリー毎の記事のNSSet型に格納したもの)に格納し、カテゴリーエンティティの記事に登録する。
処理は記事一覧のFetchedResultControllerが存在するViewControllerクラスにて行う。
ハマったこと
既に記事エンティティのFetchedResultControllerが存在しているが、記事データに紐づけるためのカテゴリーManagedObjectを特定できない。
試み : NSFetchedResultControllerをもう1つ呼び出す
tableViewDelegateの:cellForAtIndexPathにてfetchedResultControllerをindexPath毎に呼び出しているので、カテゴリー用のFetchedResultControllerを呼び出せばいいのではないのか?
という安易な考えでもう一つ呼び出し、実装してみた!
NSPredicateにてカテゴリー名を指定して絞り込みをかける。
- (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;
}
データ保存部分
- (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を取得
- (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];
}
保存部分
- (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