iPhoneでTableViewに動的追加できない

このQ&Aのポイント
  • iPhoneでUITableViewを使ってWebから取得した情報を表示しようとしていますが、非同期にセルを追加することができません。
  • テストアプリを作成していますが、初期状態が空欄の場合や挿入時のアニメーションに関して問題が発生しています。
  • (1)の初期値設定や(5)のセクション表示に関連してエラーが発生しているようです。
回答を見る
  • ベストアンサー

iphoneでTableViewに動的追加できない

UITableViewでWebから取得した情報を表示したく、非同期にCellを追加する テストアプリを書いていたのですが、わからない点がいくつかあります。 以下は非同期追加のテストコードで、実行するとリストに"foo"が一件だけ表示され 2秒おきにリストに”bar”が追加されます。 @interface AddRowTableViewController : UITableViewController { NSMutableArray *dataSouce; } -(void)onTimer:(NSTimer*)timer; @end @implementation AddRowTableViewController - (void)viewDidLoad { // 初期値は空欄 dataSouce = [[NSMutableArray alloc] init]; // (1) // 初期値としてfooを持つ //dataSouce = [[NSMutableArray alloc] initWithObjects:@"foo", nil]; // (1)' // 2秒ごとにbarを追加するためにインターバルタイマをセット [NSTimer scheduledTimerWithTimeInterval:2.0f target:self selector:@selector(onTimer:) userInfo:nil repeats:YES]; } // 2秒ごとに挿入のために呼ばれる -(void)onTimer:(NSTimer*)timer { // barを追加 [dataSouce addObject:@"bar"]; [self.tableView beginUpdates]; NSIndexPath* path = [NSIndexPath indexPathForRow:0 inSection:0]; // (2) [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationTop]; [self.tableView endUpdates]; // (3) [self.tableView reloadData]; // (4) } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [dataSouce count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *id = @"default-cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:id]; if(!cell){ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:id]; [cell autorelease]; } cell.textLabel.text = [dataSouce objectAtIndex:indexPath.row]; return cell; } #if 0 // (5) - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { if([dataSouce count] > 0) return 1; else return 0; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { // テストなので、聞かれたらTitleと答えておく return @"title"; } #endif @end このプログラムは一応動作するのですが、少し変えると期待通りに動作しません。 疑問1 コード中の(1)をコメントアウト及び(1)’をコメントインした状態で、初期値として "foo"が画面に表示された状態からスタートするようになりますが、このとき (2)で先頭に挿入するように記載していますが、実際には2行目に挿入されます。 foo bar bar 例えば4秒後にはこんな感じに並びます。なぜでしょうか? 疑問2 (4)のコードを書くと挿入時にアニメーションしません。(4)のコードを書かないとbarではなく fooが追加されたように見えます。スクロールしてフレームアウト/インなどの動作が あるとセルがリロードされ正しくbarになります。 挿入アニメーションを有効にしつつ最新データを参照させるにはどうしたらよいのでしょうか? 疑問3 (5)を#if 1とすることでセクションが表示されるようになりますが、このときに 初期値として何かあれば追加できますが、初期状態が空欄の場合に追加できず (3)のコードがSIGABRTを発行してしまいます((1)だとNG、(1)’だと通る)。 空欄のセクション付きリストにCellを挿入するにはどうしたらよいでしょうか? 経験が浅く、非常識なコードになっているのではないかと思いますが、 どうにも自力ではこれ以上進めなくなってしまいました。 上記1~3の一つでもいいので、なにかヒントをいただけないでしょうか? 未検証のカンによるアドバイスも歓迎です、こちらで検証させて頂きます。 どうかよろしくお願い致します。

質問者が選んだベストアンサー

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

> 疑問1 // barを追加 [dataSouce addObject:@"bar"]; [self.tableView beginUpdates]; NSIndexPath* path = [NSIndexPath indexPathForRow:0 inSection:0]; // (2) 引用中の1行目を、書き換えます。 [dataSouce insertObject: @"bar" atIndex: 0]; NSMutableArrayの「addObject:」は、配列の末尾にオブジェクトを追加します。 > 疑問2 「-(void)onTimer:(NSTimer*)timer」の内容を、次のように変更してください。 [dataSouce insertObject:@"bar" atIndex: 0]; if ([dataSouce count] > 0) { NSIndexPath* path = [NSIndexPath indexPathForRow:0 inSection:0]; [self.tableView beginUpdates]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationTop]; [self.tableView endUpdates]; } else { [self.tableView reloadData]; } UITableViewのリファレンス(http://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/)、「beginUpdates」の説明に…… You should not call reloadData within the group; とあります。 > 疑問3 テーブルセルがなにもない状態から、テーブルセルがある状態へのアニメーションはできないということなのでしょう。上記の変更をすれば、こちらも解消するはずです。 エラー「SIGABRT」は、内容のないNS(Mutable)Arrayに対して、要素を参照したから、発生したのだと考えられます。

jjk65536
質問者

お礼

丁寧にコードを読んでいただいてありがとうございます! ご指摘いただいた修正で完璧に動作しました。本当にありがとうございます! Appleのドキュメントを読むことを怠ったのが最大の問題ですね。 今後は読むようにします。

その他の回答 (1)

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

No.1の訂正です。 変更したコードのうち、 if ([dataSouce count] > 0) { を if ([dataSouce count] > 1) { に訂正します。すみません。

関連するQ&A

  • iphoneアプリ開発での変数の受け渡し

    最近iPhoneアプリ開発を始めた者です。 変数の受け渡しについて質問があり、投稿させていただきました。 以下のコード内で、 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 以下で設定したIDに入ったデータを、 -(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)senderの中のIDに受け渡したいのですが、どうやら2つのIDが繋がっていません。 自分自身あまりまだ理解できていないこともあり、ざっくりとした聞き方で申し訳ありません。 初歩的な質問だとは思うのですが、なにとぞご教授お願いします。 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 2; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if(cell == nil){ cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } if (indexPath.row == 0){ cell.textLabel.text = @"東京"; }else{ cell.textLabel.text = @"大阪"; } int ID = indexPath.row; return cell; } -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [self performSegueWithIdentifier:@"mySegue" sender:self]; } -(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"mySegue"]) { SecondTableViewController *viewCon = segue.destinationViewController; viewCon.myValue = ID; } }

  • iphoneアプリ 画像反転の方法

    もしとくに反転のコード組まなければ、実機上でtableviewのcellをクリックすると、反転して青くなって、画面が遷移されます。 考えているのは、回転ではなく反転です。 今回やりたいのは、tableviewのcell上にグレーの画像を貼っておいて、それをクリックすると黒の画像に反転する方法です。 gray.pngを貼りつけてグレーの画面にはできているのですが、 1、黒の画像(black.png)をどうやって貼るのか 2、cellをクリックしたときにどうやってグレー画像から黒画像に反転するのか の2点を教えて頂けたら幸いです。よろしくお願いします。 下記、コードになります。 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return 2; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } if ([indexPath row]==0) { UIImage *image = [UIImage imageNamed:@"gray1.png"]; cell.imageView.image = image; }else if ([indexPath row]==1) { UIImage *image = [UIImage imageNamed:@"gray2.png"]; cell.imageView.image = image; } return cell; }

    • ベストアンサー
    • Mac
  • iphoneプログラミング UITableの複数表示

    すいません、基本的なことだとは思うのですが、どうしても分からないため質問させてください。 UITableView を2つ並べてそれぞれに別々の値を入れていきたいのですがどうすればできますか?? - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *MyIdentifier = @"MyIdentifer"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease]; } cell.text = [listOfContents objectAtIndex:indexPath.row]; return cell; } この関数だとUITableの個別の識別ができないため2つとも同じ値が入ってしまいます。

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

    tableviewcellにチェックマークを付けるだけの簡単なコードですが、なぜかチェックマークを付けたセルとは別のセルにまでチェックマークがついてしまっています。 また、激しくスクロールするとさっきまで付いていたチェックマークが外れていたりとさらに酷い状態に・・・。 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark; UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; if (cell.accessoryType == UITableViewCellAccessoryCheckmark) cell.accessoryType = UITableViewCellAccessoryNone; else cell.accessoryType = UITableViewCellAccessoryCheckmark; [tableView deselectRowAtIndexPath:indexPath animated:YES]; } いろんなサイトで見ても上記のコードが最もよく見るコードでした。 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *CellIdentifier = @"ButtonCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; [self updateCell:cell :CellIdentifier atIndexPath:indexPath]; return cell; } - (void)updateCell:(UITableViewCell *)cell :(NSString *)CellIdentifier atIndexPath:(NSIndexPath *)indexPath { BButton *type = (BButton *)[cell viewWithTag:1]; //Buttonはライブラリを使用 [ReturnButton typeButton:type :self.showArr[indexPath.row]]; } チェックマーク以外はUIButtonなども正常に表示されました。 心当たりがあればお願いします。

  • TableViewでセル名が表示されない

    こんにちは。 iPhoneアプリの勉強している者ですが、TableViewControllerを使いセルごとに名前を表示させようとしているのですが、タイトルのみが表示されて肝心のセル名が表示されません。 appDelegate.mにてUINavigationControllerのインスタンス及びUITableViewControllerのインスタンスを作成してUITableViewControllerのインスタンスをrootViewControllerに設定しTableViewを表示させようとしています。 プログラムの記述のどこが間違っているのか教えて頂けると大変助かります。 以下UITableViewControllerのinterfaceセクションとimplementationセクションを掲載しますので、ご指摘お願いします。 #import <UIKit/UIKit.h> @interface SampleForSimpleTable : UITableViewController { NSArray *itemes; } @end @implementation SampleForSimpleTable - (id)initWithStyle:(UITableViewStyle)style { self = [super initWithStyle:style]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; self.title = @"SimpleTable"; itemes = [[NSArray alloc] initWithObjects:@"ITME 1", @"ITEM 2", @"ITEM 3", @"ITEM 4", @"ITEM 5", @"ITEM 6", nil]; } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { #warning Potentially incomplete method implementation. // Return the number of sections. return 0; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { #warning Incomplete method implementation. // Return the number of rows in the section. return [itemes count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *identifier = @"default-cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier ]; if (!cell){ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; } cell.textLabel.text = [itemes objectAtIndex:indexPath.row]; // Configure the cell... return cell; }

  • UITableViewDataSourceエラー

    xcode 7.1 (7B91b)を使用しています。 SwiftでViewControllerにUItableViewを追加した時に、 クラスの定義でdoes not conform to protocol ‘UITableViewDataSource’エラーが発生します。 サイトで調べた結果2つのメソッドを記載することとして、下記を追加しましたが、 一向にエラーが取れません。他なにか要因がありますでしょうか?ご教示のほどよろしくお願いします。 func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ } func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{ return UITableViewCell() } 全体 class ShopListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{ } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ } func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{ return UITableViewCell() }

    • ベストアンサー
    • Swift
  • UITableViewCellのカスタマイズ

    ObjectiveCを用いてiPhoneアプリ開発の勉強をしています。 ■UITableViewCellに、様々なコントロール要素をのせて表示する方法 http://www.yoheim.net/blog.php?q=20130106 このサイトを参考に、UITableViewCellに、セルごとにボタンやラベルをなどのレイアウトを設定して表示するように取り組んでいるのですが、うまくいきません。 サイトの解説では1つ1つのセルを作る解説がされていて、1つのセルをレイアウトして表示することはできるのですが、 トップ画像のように様々なレイアウトのセルを合わせて表示する方法が解説されておらず、どうすればいいのか分かりませんでした。 TableView部分のコードは以下のように記述しています。 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 1; } -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 2; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // tableCellを取得する。 static NSString *identifier = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; } UISwitch *sw = [[UISwitch alloc] initWithFrame:CGRectZero]; // UISwitchはUIContolを継承しているので、タップされた際の動作を簡単に指定できる。 [sw addTarget:self action:@selector(tapSwich:) forControlEvents:UIControlEventTouchUpInside]; // accessoryViewに代入するときれいに動作します。 cell.accessoryView = sw; cell.textLabel.text = @"Flash Light"; return cell; } この通りに書いてシミュレータを起動すると、サイトトップ画像の一番上のセルと同じレイアウトのセルが2つ表示されます。 (Flash Light とボタンのセルです。) UISwitch *sw の行から cell.textLabel.text = @"Flash Light";の行までをswitch(indexPath.row)文の中に入れると、UISwitch *sw = ... の行でExpected expressionというエラーが出てしまうので 他のレイアウトを表示することができません。 解決策をお願いします。(_ _ )

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

    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]; で遷移してきています。 何度調べても原因がわからず困っています。心当たりはないでしょうか。

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

    XCodeでUISearchBarをUITableViewヘッダーにおいてテーブルビューの要素を検索したいのですがエラーになります。 サイズがテキスト量によって可変するカスタムセルをStoryboardで作れないのでコードで作成したんですが、その場合だとサーチバーにテキストを入力し検索を押した時点でエラーになり *** Assertion failure in -[UISearchResultsTableView dequeueReusableCellWithIdentifier:forIndexPath:], となってしまいます。 セル生成のコードは以下になります - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ItemTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; //ココでエラー NSDictionary *dic; if (tableView == self.searchDisplayController.searchResultsTableView) { dic = self.searchResult[indexPath.row]; } else { dic = self.itemArr[indexPath.row]; } cell.title.text = dic[@"title"]; cell.label.text = dic[@"detail"]; CGSize textSize = [dic[@"detail"] sizeWithFont:[UIFont systemFontOfSize:13] constrainedToSize:CGSizeMake(300, 200) lineBreakMode:NSLineBreakByWordWrapping]; cell.label.frame = CGRectMake(10, 35, textSize.width, textSize.height); return cell; } Storyboard上のprototypecellなら問題なく動作するのですが、どうしてもコード生成のカスタムセルだとエラーになってしまうようです。 アドバイスお願いします。

  • 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に設定してみたところちゃんと表示されました。画面遷移の方法に原因があると考えられるのですが、上に書いたやり方はごくごく一般の方法だとおもうのですが・・・

専門家に質問してみよう