web-dev-qa-db-ja.com

データを非同期に更新した後にUITableViewを再描画する

データ非同期で読み込むUITableviewがあるので、テーブルビューがデータなしで表示される可能性があります。
ReloadDataメソッドに疲れましたが、テーブルビューをスクロールするまでテーブルビューは空のままで、突然データが表示されます。
テーブルビューを詳細ビューとして読み込んでアイテムを切り替えると、同じことが起こります。前のアイテムのデータが最初に表示され、テーブルビューをスクロールするとすぐに正しいデータが表示されます。
私の推測では、ReloadDataメソッドは正常に動作しますが、どうにかしてテーブルビューを再描画する必要があります。これを解決する方法に関する提案はありますか?

/ジミー

24
Jimmy Engtröm

コンテンツを非同期的に入力していると言いましたが、メインスレッドのコンテキストでreloadDataを呼び出しましたか? (コンテンツを入力するスレッドを介さない)

Objective-C

[yourUITableView performSelectorOnMainThread:@selector(reloadData)
                                  withObject:nil 
                               waitUntilDone:NO];

スウィフト

dispatch_async(dispatch_get_main_queue(), { self.tableView.reloadData() })

モノタッチ

InvokeOnMainThread(() => this.TableView.ReloadData());
55
yonel

Yonelsの回答は、ビューが現在ユーザーに表示されている場合に最適です(例:ユーザーがUITableViewに入力する再読み込みボタンを押します)。

ただし、データが非同期で読み込まれ、更新中にUITableViewが表示されない場合(例:別のビューでUITableViewにデータを追加し、UITableViewが後で表示されるuserinputによって)、UITableViewControllerviewWillAppearメソッドをオーバーライドするだけです。

- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.tableView reloadData];
}

プラスの効果は、UITableViewがデータを再読み込みするのは、新しいアイテムが追加されたときではなく、ユーザーが実際に見たいときに1回だけであることです。

4
Jay

リロードされなかったと思います。

セルを画面外にスクロールすると、…

tableView: cellForRowAtIndexPath:

…呼び出されます。したがって、リロードされます。

UITableView変数が検証されていないと思います。

UITableViewをメインビューとして使用する場合は、これを試すことができます。

[self.view reloadData];

または

[self.tableView reloadData];

2
Joey

今日も同様の問題がありました(iOS 7.0のストーリーボード)。 UIViewController内でテーブルビューを使用していました。ビューが読み込まれたとき、すべてが正常に機能していました。代議員全員が呼ばれていました。基になるdataSource(私の場合は、Array)が変更されたとき。表示されているテーブル行が更新されていませんでした。テーブルビューをスクロールしていたときのみ。

すべてを試しました。メインスレッドでreloadDataを呼び出す、ViewWillAppearでreloadを呼び出す、何もうまくいきませんでした。

私が見つけた問題。ストーリーボードで接続していなかったということです。参照Outletを持つテーブルビューの場合。dataSourceとデリゲートは設定されました。それが問題になるとは思いませんでした。最初の段階ではすべてが正常に機能していたため。

それが誰かを助けることを願っています。私はこれを見つけるためにひどい時間を過ごしました。

2
RUppal

Swift 4:

DispatchQueue.main.async { self.tableView.reloadData() }
1
Nate Uni

Yonelのソリューションを多少素朴にコピーしてそれを適切に呼び出すと、performSelectorOnMainThread:withObject:waitUntilDone:を呼び出すと症状が修正されるが、問題は修正されないことに気付きました。より大きな問題は、非同期またはバックグラウンドスレッドのコンテキストでUIを更新していることです。

これは私のコードがどのように見えるかです:

dispatch_queue_t queue = dispatch_queue_create("com.kyleclegg.myqueue", NULL);
dispatch_async(queue, ^{

  // Make API call
  // Retrieve data, parse JSON, update local properties
  // Make a call to reload table data

});

次のようになるはずです:

dispatch_queue_t queue = dispatch_queue_create("com.kyleclegg.myqueue", NULL);
dispatch_async(queue, ^{

  // Make API call
  // Retrieve data, parse JSON, update local properties

  dispatch_async(dispatch_get_main_queue(), ^{
    // Now make the call to reload data and make any other UI updates
    [self.tableView reloadData]
  });

});

onlyを行う必要がある場合は、[self.tableView reloadData]を呼び出すことです。同じ目的を達成するため、performSelectorOnMainThread:withObject:waitUntilDone:を使用することはおそらく問題ありません。しかし、全体像で何が起こっているかを認識する必要もあります。また、単にテーブルをリロードするだけではなく、より多くのUI作業を行っている場合は、そのすべてのコードもメインキューに配置されます。

参照: 簡潔な例 GCDを使用し、バックグラウンドとメインスレッドを管理する方法。

0
Kyle Clegg