iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
Core Data について調べたことをまとめてみる。
管理オブジェクトコンテキスト(NSManagedObjectContext)がレコード(管理オブジェクト)を管理。Core Dataではレコードをエンティティと呼ぶ。
レコードを格納するファイルは永続オブジェクトストア(Persistent Object Store)が管理し、管理オブジェクトコンテキストとは永続ストアコーディネータ(Persistent Store Coordinator)を経由して関係付けられる。例えば、SQLiteのファイル"demo.sqlite"にデータを読み書きする、管理オブジェクトコンテキストを生成するサンプルコードは、以下のとおり。
/* 例えば、Demo.xcdatamodeldを読み込む */
NSManagedObjectModel *mom = [NSManagedObjectModel mergedModelFromBundles:nil];
/* 永続ストアコーディネータ */
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
/* 永続オブジェクトストア */
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDiretory, NSUserDomainMask, YES);
NSString *documentDirectory = [documentDirectories objectAtIndex:0];
NSString *path = [documentDirectory stringByAppendingPathComponent:@"demo.sqlite"];
NSURL *storeURL = [NSURL fileURLWithPath:path];
NSError *error = nil;
if (![psc addPersistentStoreWithType:NSSQLiteStireType
configuration:nil
URL:storeURL
options:nil
error:&errir]) {
[NSException raise:@"Open failed"
format:@"Reason: %@", [error localizedDescriptoin]];
}
/* 管理オブジェクトコンテキスト */
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoodinator:psc];
/* Undo Managerを利用しない */
[moc setUndoManager:nil];
保存するサンプルコードは、以下のとおり。
NSError *error = nil;
BOOL result = [moc save:&error];
if ((! result) || (error)) {
NSLog(@"Error: %@", [error localizedDescriptoin]);
}
管理オブジェクトコンテキストに対してデータを検索するのに必要なのがフェッチ要求。
フェッチ要求には、エンティティ名(必須)と述語オブジェクト(Predicate)、整列記述子オブジェクト(Sort Descriptor)の配列(Sort Orderings)が指定できる。例えば、全レコードを"num"順に整列して取得するサンプルコードは、以下のとおり。
/* フェッチ要求 */
NSRetchRequest *request = [[NSRetchRequest alloc] init];
/* エンティティ名 */
NSEntityDescription *ed = [[mom entitiesByName] objectForKey:@"DemoItem"];
[request setEntity:ed];
/* 整列記述子オブジェクト */
NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey:@"num"
ascending:YES];
[request setSortDescriptors[NSArray arrayWithObject:sd];
/* フェッチ */
NSError *error = nil;
NSArray *response = [moc executeFetchRequest:request error:&error];
if (! response) {
[NSException raise:@"Fetch failed"
format:@"Reason: %@", [error localizedDescriptoin]];
}
NSArray *demoItemMutableArray = [[NSMutableArray alloc] initWithArray:response];
UITableViewを使っている場合、フェッチはNSFetchedResultsControllerが利用できる。
NSError *error = nil;
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:moc
sectionNameKeyPath:nil
cacheName:@"Root"];
if (![fetchedResultsController performFetch:&error]) {
[NSException raise:@"Fetch failed"
format:@"Reason: %@", [error localizedDescriptoin]];
}
管理オブジェクト(NSManagedObjectのサブクラス)の初期化は、initWithEntity:insertIntoManagedObjectContext:、awakeFromInsert、awakeFromFetchのいずれかをオーバーライドする。
- (void)awakeFromInsert
{
[super awakeFromInsert];
/* 独自の初期化コード */
}
- (void)awakeFromFetch
{
[super awakeFromFetch];
/* 独自の初期化コード */
}
管理オブジェクトの追加と削除は、以下の感じ。
/* 追加 */
DemoItem *item = [NSEntityDescription insertNewObjectForEntityForName:@"DemoItem"
inManagedObjectContext:moc];
[demoItemMutableArray addObject:item];
/* 削除 */
[moc deleteObject:item];
[demoItemMutableArray removeObjectIdenticalTo:item];
管理オブジェクトコンテキスト内では、管理オブジェクトは一意なので、フェッチ要求したオブジェクトに対応する管理オブジェクトが管理オブジェクトコンテキストに存在していたら、それをフェッチ結果として返す。
管理オブジェクトは、フェッチされたら管理オブジェクトコンテキストに存在する。管理オブジェクトの使用をやめれば、自動的に解放される。
複数の管理オブジェクトコンテキストが、一つの永続ストアコーディネータを介して、複数の永続オブジェクトストアとつながるということも可能。
NSPersistentDocumentはNSDocumentのサブクラスで、自動で管理オブジェクトコンテキストと永続オブジェクトストアを生成する。
管理オブジェクト(NSManagedObjectのサブクラス)とは、管理オブジェクトモデルで定義できる。エンティティを記述したものをメタデータと呼んでいる。