0

これが私の問題です。私のアプリのホームページには、最大3つのセクションを保持できるシンプルなUITableViewがあり、2つのセクションにはそれぞれ最大3つのアイテムがあり、3番目のセクションには最大6つのアイテムを保持できます。

各セクションには、に関連付けられたヘッダーがあります。

実際のコンテンツはWebからのものであり、リクエストを行い、サーバーがデータを送信し、NSXMLParserで応答を解析し、各セクションのデータを保持する配列(3つの配列)を作成し、セクションの参照を保持する別の配列を作成します。表示する必要があります。

次に、最後に[myTableView reloadData]を呼び出してコンテンツを更新し、テーブルを再描画します。ユーザーは、コンテンツを自分で更新することもできます。そのために、Facebookアプリと同じようにプルトゥリフレッシュメカニズムを使用しています。

pull-to-refreshを使用してコンテンツを更新すると、[myTableViewreloadData]も呼び出されます。コンテンツを更新すると、厄介なクラッシュが発生し、テーブルのレイアウトを変更する必要があります(たとえば、テーブルには現在3つのセクションがすべて保持されており、reloadDataを実行すると、1つのセクションのみが表示されます)。

デバッガーを使用して問題を追跡しました。これが私が見つけたものです:

  1. ユーザーがテーブル全体を50ピクセル程度プルダウンしてから、離します
  2. テーブルを「上」にして、「読み込み中」メッセージとテーブルの上部にアニメーション化されたUIActivityIndi​​catorViewを表示する320x50ビューに対応するアニメーションが開始されます
  3. 更新がトリガーされ、バックグラウンドタスクで新しいWebサービスリクエストを作成し、新しいデータを取得し、配列を解析して更新し、最後にメインスレッドでreloadDataを実行します
  4. その間、更新がすべてを実行している間、UITableViewはまだデリゲートメッセージを次の宛先に送信することに気づきました。
    • tableView:viewForHeaderInSection:
    • tableView:cellForRowAtIndexPath:

これは、テーブルを「移動」して新しいセル/ヘッダーを表示するプルトゥリフレッシュアニメーションが原因で発生すると思います。したがって、上記を呼び出します。

問題は、セクションのデータを保持する配列とセクション配列自体が同時に変更されるため、これがひどいクラッシュを引き起こすことです。

これが発生した場合、デリゲートメソッドは、間違ったコンテキストでアイテム/セクションの更新/まだ更新されていない配列を使用している可能性があります。つまり、前に

  • numberOfSectionsInTableView:
  • tableView:numberOfRowsInSection:

更新されたアレイの新しい構造を適切に更新する機会があります。

コードサンプルのない長い話であることは知っていますが、問題をすでに知っていて(少なくとも私が知っていることを願っています)、誰かが私のポイントを見た場合、誰かがこの同期の問題を修正するために正しい方向に私を向けることができるかもしれないと考えました。

読んでくれてありがとう!

後で編集

問題がどこにあるかを見つけました。私のpull-to-refreshメカニズムは、次のようなstopLoadingコールバックを使用します。

- (void)stopLoading 

{isLoading = NO;

// Hide the header
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDidStopSelector:@selector(stopLoadingComplete:finished:context:)];
self.myTableView.contentInset = UIEdgeInsetsZero;
[refreshArrow layer].transform = CATransform3DMakeRotation(M_PI * 2, 0, 0, 1);
[UIView commitAnimations];

}

ある時点で、テーブルのcontentInsetをリセットし、UIEdgeInsetsZeroに設定しました。これと、バックグラウンドリフレッシュがメインスレッドに戻った後、reloadDataの前にstopLoadingを呼び出していたという事実は、間違った瞬間に間違ったデリゲートコールバックをトリガーしました。

したがって、テーブルのcontentInsetへの変更とreloadDataの間のタイミングの問題でした。

4

1 に答える 1

0

テーブルビューに使用されるデータストアを別のスレッドから更新しているようです。これは良い考えではありません。データは簡単に一貫性のない状態になる可能性があり、使用しているコンテナーはいずれにせよスレッド セーフではない可能性があります。

正しい方法は、このデータをメイン スレッドからのみ更新することです。また、行などを挿入する方法を確認したい場合があります。これにより、完全なリロードがほとんど必要なくなります。また、新しいデータのために 1 つのセルだけを更新したい場合は、そのセルを更新するだけです。

于 2011-04-19T11:58:37.843 に答える