CS193p - Lecture 14

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の内容 次の記事>