UITableViewの処理速度について

このQ&Aのポイント
  • UITableViewの処理速度について質問です。
  • SLRequestを使いSNSからデータを取得し、UITableViewで表示しています。非同期で通信しているので、numberOfSectionsInTableViewやnumberOfRowsInSectionは数ミリ秒で処理されますが、cellForRowAtIndexPathに入るまでに数十秒かかってしまいます。
  • 具体的には、データを取得し配列にセットしてからテーブルビューをリロードする処理までが遅く、その原因がわかりません。
回答を見る
  • ベストアンサー

UITableViewの処理速度について

いつもお世話になっております。 SLRequest を使いSNSからデータを取得し、取得したデータをUITableViewで表示しております。 performRequestWithHandler を利用し、非同期で通信しております。 blockで、取得したデータをfot分で配列にセットし、その後、テーブルビューをリロードさせております。 numberOfSectionsInTableView、numberOfRowsInSection までは、数ミリ秒で処理されるのですが cellForRowAtIndexPath に入るまでに、数十秒かかってしまいます。 恥ずかしながら、どのスレッドが時間を使っているのか検討がつきません。 流れ -(void)getData { NSLog(@"■■■  ー (1) ー  ■■■"); 通信準備 NSLog(@"■■■  ー (2) ー  ■■■"); [xxxxxxxx performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) { データを辞書にセット NSLog(@"■■■  ー (3) ー  ■■■"); for (NSDictionary *data in data[@"data"]) { 配列にセット } NSLog(@"■■■  ー (4) ー  ■■■"); [テーブルビュー reloadData]; }]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)TableView { NSLog(@"■■■  ー (5) ー  ■■■"); snip } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSLog(@"■■■  ー (6) ー  ■■■"); snip } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"■■■  ー (7) ー  ■■■"); snip } 2014-07-26 15:17:08.848 test[583:60b] ■■■  ー (1) ー  ■■■ 2014-07-26 15:17:08.874 test[583:60b] ■■■  ー (2) ー  ■■■ 2014-07-26 15:17:08.896 test[583:60b] ■■■  ー (5) ー  ■■■ 2014-07-26 15:17:08.921 test[583:60b] ■■■  ー (6) ー  ■■■ 2014-07-26 15:17:09.306 test[583:1303] ■■■  ー (3) ー  ■■■ 2014-07-26 15:17:09.332 test[583:1303] ■■■  ー (4) ー  ■■■ 2014-07-26 15:17:09.333 test[583:1303] ■■■  ー (5) ー  ■■■ 2014-07-26 15:17:09.335 test[583:1303] ■■■  ー (6) ー  ■■■ 2014-07-26 15:17:49.883 test[583:1303] ■■■  ー (7) ー  ■■■ 2014-07-26 15:17:49.931 test[583:1303] ■■■  ー (7) ー  ■■■ 2014-07-26 15:17:49.942 test[583:1303] ■■■  ー (7) ー  ■■■ 空のテーブルビューができていて、スクロールさせると表示されます。 よろしく、お願い致します。

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

  • ベストアンサー
回答No.1

このログからすると、numberOfRowsInSectionの中の処理で 時間がかかっているんじゃないかなと思いました。 numberOfRowsInSectionの最後にログを入れると、 そのあたりがはっきりすると思います。 SNS系のAPIはあまり使用したことないので、かなりあてずっぽうですが、 numberOfRowsInSectionで全体のテーブルサイズを得るために、 同期的に全データを読み込むようなAPIを呼び出したりしてないでしょうか? numberOfRowsInSectionで返すテーブルサイズは、今読まれている データのサイズを返すようにし、非同期に読み込みが完了する たびにnumberOfRowsInSectionが返す値を増やすような設計に していればうまくいくんじゃないかなと思いました。 以上、詳しい処理方式が説明されてないので、勝手な想像での アドバイスです。 あと、どのスレッドが時間を使っているかわからないとのこと ですが、今回のようなケースだと、数十秒の時間がかかっている 時に、デバッグエリアの実行中断/再開ボタンで実行を一時中断させ、 その時のコールスタックの状態を調べれば、何が動いているか わかると思います。 (参考) Debug AreaのExecution control button https://developer.apple.com/library/mac/recipes/xcode_help-debugger/articles/about_debug_area.html Debug Navigatorのcall stacks https://developer.apple.com/library/mac/recipes/xcode_help-debug_navigator/articles/about_debug_navigator.html

RYO-88
質問者

お礼

いつもご解答、本当にありがとうございます。 numberOfRowsInSection では、配列の数を、そのまま返していたので処理に時間はかかっておりませんでした。 >非同期に読み込みが完了する >たびにnumberOfRowsInSectionが返す値を増やすような設計に >していればうまくいくんじゃないかなと思いました。 今回は、取得する件数が少ないため一度に、返していましたが 今後、件数の多いテーブルビューを使う時は、このような設計で行きたいと思います。 教えて頂きました方法で、コールスタックの状態を調べたところ performRequestWithHandler での処理が終わっていないことが解りました。 根本的な解決にはなっていませんが、テーブルビューのリロード処理の スレッドを分けたところ問題なく動くようになりました。 開発自体は仕事で行っているのですが、スマホアプリは独学の趣味でして、こういうアドバイスは本当にありがたいです。 本当に、ありがとうございました。

関連するQ&A

  • 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
  • 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プログラミング 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つとも同じ値が入ってしまいます。

  • 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で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の一つでもいいので、なにかヒントをいただけないでしょうか? 未検証のカンによるアドバイスも歓迎です、こちらで検証させて頂きます。 どうかよろしくお願い致します。

  • 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
  • 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; }

  • objective-Cについてご相談があります。

    xcode6でMasterDetailApplicationを試しております。 Master画面のセルをクリックしてDetail画面に遷移した際、 標準でDetail画面の中央に貼られているLabelに、クリックした セル内の文字列が表示される様にしたいのです。 しかし、一度目のクリックでは表示されず、二度目のクリックで初めて 一度目にクリックしたセルの文字列がLabelに表示されてしまいます。 つまり見た目上は、Labelの表示がクリックより一回分遅れるのです。 ※添付画像を参考にして下さい 以下がその部分のコードです。 ----------------------------------------------------------------------- // セグエの設定 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { [self tableView]; // セグエを「showDetail」と名付ける if ([[segue identifier] isEqualToString:@"showDetail"]) { // _cellMojiはid型のインスタンス変数。 [[segue destinationViewController] setDetailItem:_cellMoji]; NSLog(@"1番:%@",_cellMoji); } } // セル内の文字列を取得するメソッド - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // セル内の文字列を取得する UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; // 文字列データをNSString型に変換する _cellMoji = cell.textLabel.text; NSLog(@"2番:%@",_cellMoji); } ---------------------------------------------------------------------- 以上、どなたか解決策をご教示頂けないでしょうか。 何卒宜しくお願い致します。

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

  • 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なら問題なく動作するのですが、どうしてもコード生成のカスタムセルだとエラーになってしまうようです。 アドバイスお願いします。