トップ «前の日記(2012-04-22) 最新 次の日記(2012-04-24)» 編集

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|

2012-04-23 [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サイトの情報。

トップ «前の日記(2012-04-22) 最新 次の日記(2012-04-24)» 編集