2009年11月3日火曜日

メモの変更と追加

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
OneLiner開発続き。


今回はメモの変更と追加機能を追加する。



メモの変更

まず変更から。変更画面用のコントローラ DetailViewController と Xibを用意する。


DetailViewController.h
#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 の初期化

UITableViewCell の生成も OS3.0から変わっていて従来の initWithFrame:reuseIdentifier: ではなく、initWithStyle:reuseIdentifier: を使う(前者は Deprecated扱い)。セル内に複数の文字列を表示することが容易になった。



- - - -
変更、追加直後は UITableViewの表示に反映されない。スクロールして再描画をさせると表示が更新される。原因わからず。




0 件のコメント:

コメントを投稿