iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
独自にデータ管理を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は、とりあえず、雛形で用意されるファイルのコピーだ。