今回はメモの変更と追加機能を追加する。
メモの変更
まず変更から。変更画面用のコントローラ DetailViewController と Xibを用意する。
DetailViewController.h
最初のリスト画面で項目を選んだらこの変更用ビューをナビゲーションスタックへ pushして表示する。この時選択された行の NSManagedObject をへ渡してやる。この時も fetchedResultController から目的の行を簡単に取り出せる。
MainViewController.m
DetailViewController では Saveボタンが押されたら変更された内容をこの NSManagedObject へ反映する。反映後にナビゲーションスタックを popして元の画面へ戻る。
DetailViewController.m
変更の結果を UITableView へ反映させる必要がある。この目的で NSFetchedResultsControllerDelegate が用意されている。このデリゲートのメソッドを実装して NSManagedObjectContext の変更を UITableView へ反映させる。
MainViewController.m
変更、挿入、削除など操作の種類によって UITableView を変更する。上記はDevCenterで配布されているサンプルコード CoreDataBooks が参考になった。
メモの追加
続いてメモの追加。トップ画面のテキストボックスへテキストを入力し、"POST"ボタンを押すと追加できるようにする。"POST"ボタンを post: アクションへ繋げて処理を書く。
MainViewController.m
CoreData を使っていると簡単に追加できる。
追加時のログを見ると INSERT が投げられているのがわかる。
UITableView のアクセサリ
UITableViewの右側に表示されている ">" アイコン。参考本に従ってデリゲートメソッド tableView:accessoryTypeForRowWithIndexPath: を実装すると、実行時に WARNING が表示された。
OS3.0からはデリゲート(テーブル単位)ではなくセル単位で指定できるようになった。UITableViewCell の accessoryTypeプロパティに設定してやれば良い。こんな感じ。
UITableViewCell の初期化
UITableViewCell の生成も OS3.0から変わっていて従来の initWithFrame:reuseIdentifier: ではなく、initWithStyle:reuseIdentifier: を使う(前者は Deprecated扱い)。セル内に複数の文字列を表示することが容易になった。
- - - -
変更、追加直後は UITableViewの表示に反映されない。スクロールして再描画をさせると表示が更新される。原因わからず。
#import
#import
@interface DetailViewController : UIViewController {
NSManagedObject* _managedObject;
UITextField *_textTitle;
}
@property (nonatomic, retain) NSManagedObject* managedObject;
@property (nonatomic, retain) IBOutlet UITextField* textTitle;
@end
最初のリスト画面で項目を選んだらこの変更用ビューをナビゲーションスタックへ pushして表示する。この時選択された行の NSManagedObject をへ渡してやる。この時も fetchedResultController から目的の行を簡単に取り出せる。
MainViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
detailViewController.managedObject =
[fetchedResultsController objectAtIndexPath:indexPath];
[[self navigationController] pushViewController:detailViewController
animated:YES];
}
DetailViewController では Saveボタンが押されたら変更された内容をこの NSManagedObject へ反映する。反映後にナビゲーションスタックを popして元の画面へ戻る。
DetailViewController.m
- (void)save:(id)sender
{
[self.managedObject setValue:self.textTitle.text forKey:@"title"];
NSError* error = nil;
[[self.managedObject managedObjectContext] save:&error];
NSLog(@"error=%@", error);
[self.navigationController popViewControllerAnimated:YES];
}
変更の結果を UITableView へ反映させる必要がある。この目的で NSFetchedResultsControllerDelegate が用意されている。このデリゲートのメソッドを実装して NSManagedObjectContext の変更を UITableView へ反映させる。
MainViewController.m
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
switch(type) {
case NSFetchedResultsChangeInsert:
NSLog(@"NSFetchedResultsChangeInsert:");
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
NSLog(@"NSFetchedResultsChangeDelete:");
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
NSLog(@"NSFetchedResultsChangeUpdate:");
[self configureCell:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
NSLog(@"NSFetchedResultsChangeMove:");
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
// Reloading the section inserts a new row and ensures that titles are updated appropriately.
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
変更、挿入、削除など操作の種類によって UITableView を変更する。上記はDevCenterで配布されているサンプルコード CoreDataBooks が参考になった。
メモの追加
続いてメモの追加。トップ画面のテキストボックスへテキストを入力し、"POST"ボタンを押すと追加できるようにする。"POST"ボタンを post: アクションへ繋げて処理を書く。
MainViewController.m
- (IBAction)post:(id)sender
{
NSLog(@"Post message");
NSError* error = nil;
NSManagedObject* memo = [NSEntityDescription insertNewObjectForEntityForName:@"Memo"
inManagedObjectContext:managedObjectContext];
[memo setValue:self.textField.text forKey:@"title"];
[managedObjectContext save:&error];
if (error) {
NSLog(@"ERROR: %@", error);
} else {
self.textField.text = @"";
[self.textField resignFirstResponder];
}
}
CoreData を使っていると簡単に追加できる。
追加時のログを見ると INSERT が投げられているのがわかる。
2009-11-03 07:29:57.705 OneLiner[15035:207] CoreData: sql: BEGIN EXCLUSIVE 2009-11-03 07:29:57.707 OneLiner[15035:207] CoreData: sql: SELECT Z_MAX FROM Z_PRIMARYKEY WHERE Z_ENT = ? 2009-11-03 07:29:57.708 OneLiner[15035:207] CoreData: sql: UPDATE Z_PRIMARYKEY SET Z_MAX = ? WHERE Z_ENT = ? AND Z_MAX = ? 2009-11-03 07:29:57.709 OneLiner[15035:207] CoreData: sql: COMMIT 2009-11-03 07:29:57.710 OneLiner[15035:207] CoreData: sql: BEGIN EXCLUSIVE 2009-11-03 07:29:57.711 OneLiner[15035:207] CoreData: sql: INSERT INTO ZMEMO(Z_PK, Z_ENT, Z_OPT, ZTITLE, ZPHOTO) VALUES(?, ?, ?, ?, ?) 2009-11-03 07:29:57.712 OneLiner[15035:207] CoreData: sql: COMMIT 2009-11-03 07:29:57.714 OneLiner[15035:207] CoreData: sql: pragma page_count 2009-11-03 07:29:57.714 OneLiner[15035:207] CoreData: annotation: sql execution time: 0.0006s 2009-11-03 07:29:57.715 OneLiner[15035:207] CoreData: sql: pragma freelist_count 2009-11-03 07:29:57.715 OneLiner[15035:207] CoreData: annotation: sql execution time: 0.0007s
UITableView のアクセサリ
UITableViewの右側に表示されている ">" アイコン。参考本に従ってデリゲートメソッド tableView:accessoryTypeForRowWithIndexPath: を実装すると、実行時に WARNING が表示された。
2009-10-25 09:42:12.828 OneLiner[5235:207] WARNING: Using legacy cell layout due to delegate implementation of tableView:accessoryTypeForRowWithIndexPath: in . Please remove your implementation of this method and set the cell properties accessoryType and/or editingAccessoryType to move to the new cell layout behavior. This method will no longer be called in a future release.
- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellAccessoryDisclosureIndicator;
}
OS3.0からはデリゲート(テーブル単位)ではなくセル単位で指定できるようになった。UITableViewCell の accessoryTypeプロパティに設定してやれば良い。こんな感じ。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = @"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:kCellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
NSManagedObject* managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [managedObject valueForKey:@"title"];
return cell;
}
UITableViewCell の生成も OS3.0から変わっていて従来の initWithFrame:reuseIdentifier: ではなく、initWithStyle:reuseIdentifier: を使う(前者は Deprecated扱い)。セル内に複数の文字列を表示することが容易になった。
- - - -
変更、追加直後は UITableViewの表示に反映されない。スクロールして再描画をさせると表示が更新される。原因わからず。
0 件のコメント:
コメントを投稿