6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-06-10

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

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?