iTunes U スタンフォード大学のiOSアプリ開発講義のLecure 14(Core Data Demo) の講義メモです。
Core Dataのスレッドセーフティ
NSManagedObjectContextはスレッドセーフではないので、作成したスレッド内でしかアクセスしないこと。
別スレッドで処理中にアクセスしたい場合は、次のメソッドを使用する。
[コンテキスト performBlock:^{ //or performBlockAndWait:
// コンテキストへのアクセス
}];
※parentContextのスレッド上でperformBlock:を実行する場合、その変更内容を確認する前に保存してrefetchしなければならない。
Core Dataとテーブルビュー
■NSFetchedResultsController
NSFetchedResultsControllerは、Core Dataのデータとテーブルビューを結びつけるNSObjectを継承したクラスである。
このクラスは、データベースのデータの数を数えてくれるので、UITableViewDataSourceプロトコルの中のセクションの数や行の数をこれを使って指定できる。
<例>
・セクションの数
- (NSUInteger)numberOfSectionsInTableView:(UITableView *)sender
{
return [[self.fetchedResultsController sections] count];
}
・行の数
- (NSUInteger)tableView:(UITableView *)sender numberOfRowsInSection:(NSUInteger)section
{
return [[[self.fetchedResultsController sections]
objectAtIndex:section] numberOfObjects];
}
■任意のインデックスのデータ取得
- (NSManagedObject *)objectAtIndexPath:(NSIndexPath *)indexPath;
・テーブルビューのセルにデータを設定
- (UITableViewCell *)tableView:(UITableView *)sender
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = ...;
NSManagedObject *managedObject =
[self.fetchedResultsController objectAtIndexPath:indexPath];
// managedObjectのプロパティを取得する
// カスタムサブクラスがあればドット表記で取得できる
return cell;
}
・NSFetchedResultsControllerの作成
NSFetchRequest *request =
[NSFetchRequest fetchRequestWithEntityName:@“Photo”];
NSSortDescriptor *sortDescriptor =
[NSSortDescriptor sortDescriptorWithKey:@“title” ...];
request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
request.predicate =
[NSPredicate predicateWithFormat:@“whoTook.name = %@”, photogName];
NSFetchedResultsController *frc =[[NSFetchedResultsController alloc]
initWithFetchRequest:(NSFetchRequest *)request
managedObjectContext:(NSManagedObjectContext *)context
sectionNameKeyPath: (NSString *) // sectionになる属性のキーパス
cacheName:@“MyPhotoCache”; // 注意!
※cacheNameにnilを設定するとキャッシュが使用されない。casheNameを指定した場合は、キャッシュはアプリの起動をまたいで使用される。
データ選択の条件を変更したらcacheNameも別の名前にする。
※ソート順はセクションに表示するプロパティ>データの表示順にする
NSFetchedResultsControllerは、Core Dataの変更内容に合わせて内容が更新される。
そのため、refetchなどは実装する必要がない。更新されたタイミングで独自の処理をしたい場合は、次のdelegateメソッドを使用する
- (void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
// 行を更新する処理
}
■Core Dataとテーブルビューの結びつけ
NSFetchedResultsControllerのドキュメントにサンプルコードが掲載されているので、それを使えば自分でデータベースとテーブルビューのデータの同期を取る必要はない。
講義では、それをCoreDataTableViewControllerというクラスで提供している。
・使い方
このクラスを継承するサブクラスとしてテーブルビューコントローラを作成
cellForRowAtIndexPath:以外のテンプレートメソッドを削除
テーブルビューに表示する内容でNSFetchRequestを作成
作成したNSFetchRequestを使ってfetchedResultsControllerを作成
テーブルセル値の設定時にfetchedResultsControllerを使ってデータ取得
デモ(Core Dataをキャッシュとして使用)
実装手順
Photographers |
Photos By Phorographer |
DBの作成 DBファイル:UIManagedDocument インスタンス:<DB>.managedObjectContext |
|
DBのインスタンスを使ってDB検索コントローラを作成 NSFetchedResultsConroller |
|
<DBを作成した場合> ・データをDBに追加 ※データ取得に時間がかかるので別スレッドで テーブルの属性値を設定(カテゴリで) リレーション設定時にリンク先データも追加 |
|
NSFetchedResultControllerに検索条件設定
|
|
テーブルのセルデータを設定 tableView:cellForRowAtIndexPath:を実装 |
|
パブリックモデルを実装 @property Photographer * |
|
モデルのセッターで 画面タイトル設定 DB検索コントローラ作成 |
|
テーブルのセルデータを設定
|
|
Segueの実装 遷移先MVCのモデルに値を設定 |
|
Segueの実装
|
※build前にCore Dataフレームワークを追加
作成されるDBの実体
講義とは直接関係ありませんが、データベースが実際にはどういう形で存在するのか気になったので確認してみました。
講義のデモで作成したデータベースは、ファイルシステム上ではこんなふうになっていました。
データベースの実体はpersistentStoreという名前のファイルになっていました。
そして、そのファイルの中身をエディタで覗いてみるとこんな感じでした。
先頭に”SQLite format"と入っているので、やはりCore DataはSQLiteのデータベースをベースにしているみたいですね。
Core Dataの概念図
上の結果から、クラスと実体の関係を図にするとこんな感じになりそうです。
<前の記事 |
CS193p - Lecture 13 | - | CS193p 課題6の内容 | 次の記事> |
コメントをお書きください