iPhoneのTableViewでセル削除を行わせたいとき、以下のような画面を表示して行う。

holidaystableview

これを行うためにテーブルビューコントローラーはUITableViewDelegateプロトコルとUITableViewDataSourceプロトコルを実装してcommitEditingStyleメソッドを実装する必要がある。

@interface HogeTableViewController : UITableViewController &gtUITableViewDelegate ,UITableViewDataSource< {
    NSMutableArray *array
}
@end

@implementation HogeTableViewController
...
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]  withRowAnimation:UITableViewRowAnimationFade];
    // Delete the row from the data source
    NSInteger row = [indexPath row];
    [self.array removeObjectAtIndex: row];
    }
}
@end

(EditModeに変更するコードは省略)

テーブルビュー上でセルを削除すると上のcommitEditingStyleが呼ばれる。
しかし、上のコードではdeleteRowsAtIndexPathsメソッドを呼んだ時点でエラーになってしまう。
どうやらテーブルビューはデータソースの状態をモニターしているらしく、上のコードで言うとarray変数の要素数とテーブルビューのセル数が違っているとエラーではねる仕様になっているらしい。
データソースはおそらくヘッダーファイルで一番最初に宣言されている配列をデータソースとしているのではないかと思われる。
従って、以下のようにデータソースの要素を削除してからテーブルビューのセルを削除すると正常に終了する。

少し気持ち悪い仕様だが、iPhoneでソフトウェアを作るかぎりでは仕方ないのだろう。

iPhoneのアプリでよくあるインターフェースがリストを表示してアイテムを選択すると詳細ページを表示するというパターンだ。

table

上のリストの一つをタップすると詳細ページが表示される。
これだけだったら以下のコードをtableViewControllerに追加すれば実現できる。

tableViewController.m

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	// テープルコントローラーで何番目のセルが選択されたか
	NSInteger row = [indexPath row];
       // nibファイルを読み込んで詳細ページのコントローラーを生成
	if (detailViewController == nil){
		LocationMemoDetailViewController *memoDetail = [[LocationMemoDetailViewController alloc] initWithNibName:@"MemoListDetailView" bundle:nil];
		detailViewController = memoDetail;
		[memoDetail release];
	}
       // 詳細ページへ切り替え
	[navController pushViewController:detailViewController	animated:YES];
}

上のコードはtableViewControllerのリストアイテムがタップされたときに呼ばれるdidSelectRowAtIndexPathメソッドである。
コードのdetailViewControllerが詳細ページのコントローラークラスである。
これで詳細ページに何か情報を渡したいい場合は以下のようなコードを追加すればよさそうに思われるだろう。

tableViewController.m

detailViewController.nameField.text = @"山田 太郎";

ここでnameFieldは詳細ページ上にあるUITextFieldのオブジェクトである。
しかし、これで詳細ページを表示しても設定された値は表示されない。
どうやら詳細ページの中身が生成されるのは表示されるときのようなのでnibファイルを読み込んだだけではアクセスできないようである。
この場合、detailViewControllerクラスにテキストフィールドに表示するデータを一時保管しておく変数を追加する。

detailViewController.h

@interface LocationMemoDetailViewController : UIViewController {
...
NSString *name;
}
@propety(nonatomic,retain) NSString* name
</pre>

detailViewController.m
<pre name="code" class="java">
...
@synthesize name

そしてtableViewController側にはviewWillAppearメソッドを以下のように追加する。

- (void)viewWillAppear: (BOOL) animated {
	self.nameField.text = self.name;
}

つまり、詳細ページが表示されたときに一時保管してある文字列をテキストフィールドに設定するのである。

このあたりはiPhoneのUIの中身が隠蔽されているのでわかりにくい部分だ。
APIを呼ぶだけで結構な仕事をしてくれるので楽なのだが、その引き換えに中の動きがわかりずらくとまどうことが多い。
このあたりもiPhoneで開発する上でのノウハウなのだろう。

iPhone SDK 3でターゲットを「Simulator – 3.0|Debug」にしてビルドすると(プロジェクト名)_Prefix.pchファイルで以下のようなエラーが出ることがある。

error: syntax error before ‘AT_NAME’ token
error: syntax error before ‘}’ token
fatal error: method definition not in @implementation context

原因はコンパイラーのバージョンによってiPhone OS 3.0用実行ファイルのコンパイルができないようである。
回避方法は以下の通り。

1  XCodeのメニュー「プロジェクト」-「プロジェクト設定を編集」を選択する。
2  一番上のタブの「ビルド」を選択する。
3  「コンパイラのバージョン」項目を選択する。
4  「C/C++コンパイラのバージョン」の値を「GCC 4.0」にする。
5  「C/C++コンパイラのバージョン」が選択されている状態でウィンドウの左下隅にある歯車アイコンをクリックし、「ビルド設定条件を追加」メニューを選択する。
6  新しいエントリーが追加されるので一番左の項目をクリックし、「Device – iPhone 3.0」を選択する。そして一番右の項目をクリックし「GCC 4.2」を選択する。
7  もう一度5,6の作業をくりかえし、左の項目「Simulator – iPhone3.0」を選択し右の項目「GCC 4.2」を選択する。