CoreDataでデータ保存

2010/07/15

CoreDataの基礎 その1|CoreDataの基礎 その2|CoreDataの基礎 その3|CoreDataの基礎 その4

実際にデータを保存してみる。

結論から言ってハマりました。。。

まず、.xcdatamodelでのEntityの設定で以下のようにしました。

・Entity名:User ・アトリビュート キー:no int16 氏名:name String

で、ですね、「SELECT * FROM User WHERE no = 2;」みたいなことをやろうと、

NSPredicate *pred = [NSPredicate predicateWithFormat:@"(no = %d)", i];

を実行してもまったくもって抽出できない! 文字列のフォーマットが駄目なのか?と何度も検証したが何度やってもうまくいかないorz で、判明したのが、

アトリビュート名で「no」を使うと抽出できなかった・・・

SQLiteの予約語なのか?Core Dataで利用できないのか?わからないが、アトリビュート名を 「no」→「id」に変更したらうまくいきました。 ※idはObjective-Cの予約語なのでこれも命名的によろしくないとは思いますが・・・

サンプル

駄目駄目なかなり汚いコードですが・・・まぁ、調査と言う事で。

- (void)applicationDidEnterBackground:(UIApplication *)application {
    Core_Data_persistenceAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    NSError *error;
    
    for (int i = 1; i <= 4; i++) {
        NSString *fieldName = [NSString stringWithFormat:@"line%d", i];
        UITextField *textField = [self valueForKey:fieldName];
        
        NSFetchRequest *request = [[NSFetchRequest alloc] init];
        NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"User"
                                                             inManagedObjectContext:context];
        [request setEntity:entityDescription];
        
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"(id = %d)", i];
        [request setPredicate:pred];
        
        NSManagedObject *user = nil;
        NSArray *objects = [context executeFetchRequest:request error:&error];

        if (objects == nil) {
            NSLog(@"Error!");
        }
        if ([objects count] > 0) {
            //UPDATE
            user = [objects objectAtIndex:0];
        } else {
            //INSERT
            user = [NSEntityDescription insertNewObjectForEntityForName:@"User"
                                                 inManagedObjectContext:context];
        }
        
        [user setValue:[NSNumber numberWithInt:i] forKey:@"id"];
        [user setValue:textField.text forKey:@"name"];
        [request release];
    }
    [context save:&error];
}

- (void)viewDidLoad {
    NSLog(@"viewDidLoad");
    Core_Data_persistenceAppDelegate *appDelegate =
    [[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"User"
                                                         inManagedObjectContext:context];
    [request setEntity:entityDescription];
    
    NSError *error;
    NSArray *objects = [context executeFetchRequest:request error:&error];
    [request release];
    if (objects == nil) {
        NSLog(@"Error!");
    }
    for (NSManagedObject *oneObject in objects) {
        NSNumber *rid = [oneObject valueForKey:@"id"];
        NSString *name = [oneObject valueForKey:@"name"];
        UITextField *textField = [self valueForKey:fieldName];
        textField.text = name;
    }
    
    UIApplication *app = [UIApplication sharedApplication];
    [[NSNotificationCenter defaultCenter] 
     addObserver:self
     selector:@selector(applicationDidEnterBackground:)
     name:UIApplicationDidEnterBackgroundNotification
     object:app
     ];
    [super viewDidLoad];
}

保存処理の流れ

(1) applicationDidEnterBackgroundが呼び出される (2) ApplicateionDelegateからNSManagedObjectContextを取得 (3) NSEntityDescription entityForNameでUser Entityを取得 (4) データベースリクエストである (5) NSFetchRequest setPredicateでクエリーを設定

SELECT * FROM User WHERE id = %d

(6) (NSArray *) NSManagedObjectContext executeFetchRequest:NSFetchRequestでクエリー実行 (7) 既にデータがある場合はNSArrayの最初のデータ(NSManagedObject)取得 (8) データがない場合はNSEntityDescription insertNewObjectForEntityForNameでNSManagedObjectを新規作成 (9)setValueで各値を設定し、NSManagedObjectContext saveで保存

読み込み処理の流れ

(1) viewDidLoadが呼び出される (2) ApplicateionDelegateからNSManagedObjectContextを取得 (3) NSEntityDescription entityForNameでUser Entityを取得 (4) NSFetchRequest setPredicateでクエリーを設定 (5) (NSArray *) NSManagedObjectContext executeFetchRequest:NSFetchRequestでクエリー実行 (6) NSArrayをループして、valueForKeyでデータ設定

また、viewDidLoadでapplicationDidEnterBackgroundのObserverを設定しています。 ただ、Applicationの遷移でデータを制御するのは危険かと思うのであくまでも一例で・・・