[iOS]データ管理(その1) | Cocoa練習帳

[iOS]データ管理(その1)

独自にデータ管理をDocumentクラスで行っている著者としては、CoreDataとの付き合いは悩む部分がある。今回は曖昧にしていた部分をしっかり理解できる様、シンプルな構成のプロジェクトにCoreDataを組み込んでゆく。




プリコンパイル・ヘッダーDatum-Prefix.pchにCoreDataのヘッダーを追加する。




#ifdef __OBJC__
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
#endif



アプリケーションのコントローラとなるAppDelegateに、CoreData関連のプロパティとメソッドを追加する。




@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
 
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;



そして、AppDelegateにCoreData関連のコードを追加する。


アプリケーション終了時に保存。




- (void)applicationWillTerminate:(UIApplication *)application
{
    [self saveContext];
}



突然、アプリケーションが停止される事を考えて、バックグラウンドに回った際にも保存する等、工夫する余地はあると思う。




保存のメソッドだ。




- (void)saveContext
{
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        } 
    }
}



これは雛形で用意されるメソッドそのままだが、abort()関数の呼び出しは、マズイと思う。リジェクトもされるのでは?




雛形のコードは巧妙で、プロパティ呼び出しが、メソッド呼び出しになっていて、必要なタイミングで生成されるようになっている。




- (NSManagedObjectContext *)managedObjectContext
{
    if (__managedObjectContext != nil) {
        return __managedObjectContext;
    }
    
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        __managedObjectContext = [[NSManagedObjectContext alloc] init];
        [__managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return __managedObjectContext;
}
 
- (NSManagedObjectModel *)managedObjectModel
{
    if (__managedObjectModel != nil) {
        return __managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Datum" withExtension:@"momd"];
    __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return __managedObjectModel;
}
 
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator != nil) {
        return __persistentStoreCoordinator;
    }
     
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Data.sqlite"];
    
    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    
    
    return __persistentStoreCoordinator;
}



SQLiteファイルの保存先を返すメソッド。ただ、Documentディレクトリでいいのか?隠すように場所でもいいのでは?という疑問はある。




- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}



モデルを定義したファイルDatum.xdatamodeldは、とりあえず、雛形で用意されるファイルのコピーだ。




ソースコード

GitHubからどうぞ。

https://github.com/murakami/workbook/tree/master/ios/Datum - GitHub




関連情報

Core Data Programming Guide

Developerサイトの情報。