2009年10月13日火曜日

NSFetchedResultsController を使って CoreData を表示する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
iPhone Dev Center から CoreDataBooks というサンプルコードを入手してソースを読む。なるほど NSFetchedResultsController を使うと UITableView で CoreData を使うのが楽になりそうだ。

CoreDataBooks の動作はこんな感じ。










リストに詳細表示、それと項目の編集を行う3つのビューから構成される。データの格納に CoreData を採用していて UITableView との連携に NSFetchedResultsController を使っている。

NSFetchedResultsController の使い方を理解するためにこのコードを参考にしつつ、(テーブルが一つで)構造が単純な OneLiner を NSFetcedResultsController を使うバージョンに書き換えてみる。

MainViewController.h

@interface MainViewController : UIViewController {

NSPersistentStoreCoordinator* persistentStoreCoordinator;
NSManagedObjectContext* managedObjectContext;
NSFetchedResultsController* fetchedResultsController;
}


メンバ変数に NSFechedResultsController を追加。


MainViewController.m

- (void)setupFetchedResultsController
{
// [1] Persistent Store Coordinator
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];

NSError* error = nil;
NSString* filepath = [NSString stringWithFormat:@"%@/%@",
  [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0],
  @"memo.db"];

[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
  URL:[NSURL fileURLWithPath:filepath]
  options:nil
error:&error];
if (error) {
NSLog(@"[1] %@", error);
}


// [2] Managed Object Context
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:persistentStoreCoordinator];


// [3] Fetched Results Controller
// Fetch Request
NSFetchRequest* request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Memo"
  inManagedObjectContext:managedObjectContext]];
[request setIncludesSubentities:NO];

// Sort Descriptor
NSSortDescriptor* sortDescriptor =
[[NSSortDescriptor alloc] initWithKey:@"title"
ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];

// Fetched Result Controller
fetchedResultsController =
[[NSFetchedResultsController alloc]
initWithFetchRequest:request
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil
cacheName:@"Root"];
[sortDescriptor release];
[request release];
}



セットアップ用のメソッドを用意し、ここで NSPersistentStoreCoordinator, NSManagedObjectContext, NSFectedResultsController の3つのインスタンスを用意する。NSFetchedController には検索条件、ソート条件をあらかじめ渡しておく。


- (void)viewDidLoad {
    [super viewDidLoad];

[self setupFetchedResultsController];
NSError* error = nil;

if (![fetchedResultsController performFetch:&error]) {
NSLog(@"%@", error);
}
   :


View のロード時にセットアップと読み込み(performFetch)を実行する。

続いて DataSource のコーディング。

- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo =
[[fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = @"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
  reuseIdentifier:SimpleTableIdentifier] autorelease];
}
NSManagedObject* managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [managedObject valueForKey:@"title"];
return cell;
}

前回までは呼出される毎に検索をかけていたが、その部分を NSFetchedController にまかせることができるのですっきりした。UITableView 向けにつくられているので Section や NSIndexPath をそのまま扱えるのが便利。


実行してみよう。






動いた。


コンソールを見るとSQLが飛んでいるのは1回のみ(あたりまえだが)。


[Session started at 2009-10-13 06:13:39 +0900.]
2009-10-13 06:13:44.494 OneLiner[8886:207] CoreData: annotation: Connecting to sqlite database file at "/Users/hashi/Library/Application Support/iPhone Simulator/User/Applications/BF9B0A56-4CC4-428A-AB2B-FD1E20BDEAAD/Documents/memo.db"
2009-10-13 06:13:44.500 OneLiner[8886:207] CoreData: sql: pragma cache_size=1000
2009-10-13 06:13:44.501 OneLiner[8886:207] CoreData: sql: SELECT Z_VERSION, Z_UUID, Z_PLIST FROM Z_METADATA
2009-10-13 06:13:44.549 OneLiner[8886:207] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZTITLE, t0.ZPHOTO FROM ZMEMO t0 ORDER BY t0.ZTITLE
2009-10-13 06:13:44.551 OneLiner[8886:207] CoreData: annotation: sql connection fetch time: 0.0019s
2009-10-13 06:13:44.552 OneLiner[8886:207] CoreData: annotation: total fetch execution time: 0.0032s for 18 rows.



SQLiteから取得したデータの管理を NSFetechedResultsController がやってくれるのでこれはいい。

0 件のコメント:

コメントを投稿