• 締切済み

iphoneアプリ開発についての質問です

http://okwave.jp/qa/q8846564.htmlの質問に補足を付け加えたものです。 storyboardのprototype cellsでカスタムセルを4つ作成しidentifierも設定した状態で、 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static const id identifiers = { @"MetaCell", @"StatusCell", @"EvoCell", @"FormCell" }; NSString *CellIdentifier = identifiers[indexPath.section]; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 以下略 という風にしているのですが UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath: というエラーが出てしまいます。 identifierの文字列は何度見ても一致していました。 if (cell == nil) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 上記のコードを追加しても、一応エラーは出ませんが当然セルは反映せず真っ白のままです。 if (cell == nil) { if (indexPath.section == 0) { cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; } else if (indexPath.section == 1) { cell = [tableView dequeueReusableCellWithIdentifier:@"StatusCell"]; } else if (indexPath.section == 2) { cell = [tableView dequeueReusableCellWithIdentifier:@"EvoCell"]; } else if (indexPath.section == 3) { cell = [tableView dequeueReusableCellWithIdentifier:@"FormCell"]; } } 一応このようなやりかたでも試しましたが結果は同じでした。 ちなみにこのテーブルビューへは前のビューからsegueで (void)[[segue destinationViewController] initDetailDic:dic]; で遷移してきています。 何度調べても原因がわからず困っています。心当たりはないでしょうか。 *補足 問題の起こっているこのテーブルビューへは、前のテーブルビューから遷移してきているのですが試しにNavigationControllerのrootViewに設定してみたところちゃんと表示されました。画面遷移の方法に原因があると考えられるのですが、上に書いたやり方はごくごく一般の方法だとおもうのですが・・・

みんなの回答

  • harawo
  • ベストアンサー率58% (3742/6450)
回答No.1

> 上に書いたやり方はごくごく一般の方法だとおもうのですが いいや、ちっとも「一般」的ではないです。見よう見まねで書いたコードが、たまたま動いたからといって、これで正しい、「一般」的だと勘違いしてはいけません。 (別質問で、別回答者から指摘されていた「static const id identifiers = { @"MetaCell", @"StatusCell", @"EvoCell", @"FormCell" };はエラーになって、ビルドできないでしょう?」を放置したままだし……) 一般的な、というより定型的なプログラムを書くには、まずテーブル表示のメカニズムの概要を理解する必要があります。 テーブルは、基本何千行、何万行のセルがあっても、動くようになっています。ツイッターアプリなんかは、下にスクロールしていったら、いくらでも過去のツイートを表示していきます。もちろんそのとおり何千、何万のセルを配置していったら、メモリ不足でアプリが落ちてしまうので、テーブルビューには、ちょっとしたしかけが施されています。 テーブルビューにセルが10個表示されているとすると、セルの個数はせいぜい12か13個しかありません。テーブルをスクロールしたら、ビューの表示から出て行ったセルは、すぐに反対側に移動して、textLabelなどの要素を書きかえて、新しいセルのような顔をして、再表示されるのです。このメカニズムをセルの再利用(Reuse)といいます。 セルを再利用するという、UITableViewのメソッドは、2種類あります。 - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath 前者は古くからあるメソッドで、「セルを再利用する。もし再利用できるセルがなかったら、新しくセルを作る」という処理をします。 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableView *cell; cell = [tableView dequeueReusableCellWithIdentifier: @"CellIdentifier"]; if (cell == nil) { cell = [UITableViewCell initWithStyle: UITableViewCellStyleDefault reuseIdentifier: @"CellIdentifier"]; } return cell; } 後者は、セルをテーブルビューを生成した後、すぐに必要分作っておけ、後で不足しても、この命令は覚えておけよ、という処理で使います。定型ではView Controllerの「viewDidLoad」メソッドに、次のいずれかのメソッドを実装します。 - (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier - (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier 前者はInterfaceBuilderで作ったセルのプロトタイプを利用する場合、後者はプログラムでセルを作る場合のメソッドです。 実践的には、これらのメソッドを書く代わりに、Storyboard上でセルのプロトタイプを作り、そのIdentifierとコード上の再利用セルのIdentifierを一致させるという手法をとります。 以上をふまえて、4つのセルのプロトタイプを、Storyboard上で作成した場合のプログラムは、ひとつのサンプルとして、このようになります。 #import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UITableView *tableView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 4; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 1; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *identifiers[] = {@"Pattern1", @"Pattern2", @"Pattern3", @"Pattern4"}; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: identifiers[indexPath.section] forIndexPath: indexPath]; return cell; } @end