7

セットアップ:単純な配列データ ソースに基づくUICollectionVieworがあります。UITableViewそのデータ ソースのコピーをコントローラーに保持します。

今、新しいデータが利用可能であるという通知をシステムから受け取りました。アイテムが追加、削除、および位置が変更された可能性のある新しい配列を取得します。

これで、2 つのデータ オブジェクトができました。

  • UI が現在表示しているものと同期している以前の配列
  • 項目が追加、削除、移動された新しい配列

UI を新しい配列と同期させるには、多数の UI 呼び出しを生成する必要があります。の場合UICollectionView、それらは

- (void)insertItemsAtIndexPaths:(NSArray *)indexPaths
- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
- (void)deleteItemsAtIndexPaths:(NSArray *)indexPaths

また、同様の一連のメソッドがありUITableViewます。

テーブル全体をリロードしたくないのは、いくつかの項目を処理するよりもコストがかかるためです。

問題は、以前のデータ ソース配列と新しいデータ ソース配列が与えられた場合、UI 呼び出しの正しいセットを生成するにはどうすればよいか、またいつ古いデータ ソースを新しいデータ ソースに「交換」するかということです。

4

4 に答える 4

8

これは、あるテキスト ファイルと別のテキスト ファイルの間の変更の最小数を見つけて、それらの変更を適用することを目的とするdiff / patch問題とほぼ同等だと思います。その場合、実装は操作を定義します。

  • 追加または挿入
  • 消去
  • 変化する

...しかし動かない。moveを省略する理由はすぐにはわかりませんが、moveを含めると、最適な動きを見つけるために非常にコストのかかる計算が必要になるのではないかと強く思います。

したがって、操作を上記にリストしたものに制限すると、An Algorithm for Differential File Comparisonで説明されている Hunt-McIlroy アルゴリズム、またはその子孫の 1 つで、最適に近い一連の変更が検出されます。

あなたの問題と従来のdiff / patchの違いは、2 次元のテーブルがあるのに対し、diff / patchは 1 次元の項目セット (テキスト行) を扱うことです。2 次元の問題を 1 次元の問題に変換する最善の方法は、データ テーブルで行われる傾向がある変更の特定の特性によって異なります。

たとえば、テーブルがnx m列であり、変更が行ごとにグループ化される傾向にある場合、または行が全体として挿入または削除される場合、テーブルをテキスト ファイルであるかのように考えて、行ごとに差分をとります。または、変更が列にグループ化される傾向がある場合、または列が挿入または削除される場合は、列ごとに差分を実行できます。変更に個々のセルの挿入または削除が含まれる場合 (その結果、後続のセルが右または左に移動することになります)、テーブル内の各セルがテキスト ファイルの個別の行にあるかのようにテーブルを処理して、テーブルを線形化できます。行優先または列優先のいずれかの順序で。

ただし、この点で問題の詳細を知らなくても、時期尚早の最適化を避ける傾向があります。したがって、 m < nの場合は行ごと、 n < m の場合は列ごとに Hunt-McIlroy アルゴリズムを実装することから始めて、使用中のアプリケーションをしばらくプロファイリングしてから、アルゴリズムのより洗練されたバージョンまたは Hunt-McIlroy ソリューションへの問題の代替マッピングが保証されました。

さまざまなdiffアルゴリズムに関する適切な議論は、こちらの stackoverflow にあります。

于 2013-01-11T22:29:13.780 に答える
4

私は、解決できた非常によく似た問題を処理するアプリに取り組んできました。複雑な解決策を期待していましたが、それは本当に簡単でした。これを解決する方法は次のとおりです。

1)新しいアイテムを受け取る新しい配列を作成し、それを「moreItems」と呼びます。もちろん、それを合成します。

@property (nonatomic, readonly) NSMutableArray *moreItems;

2)TableViewまたはCollectionViewにリンクされているViewControllerのviewDidLoadで、この配列を割り当て/初期化します。

moreItems = [[NSMutableArray alloc] init];

3)次に、既存の配列を追加する必要があります。これは、作成したばかりの「moreItems」という名前の新しい配列に「アイテム」であるとしましょう。'addObjectsFromArray'を使用してこれを行うことができます

[moreItems addObjectsFromArray:[channel items]];

「チャネルアイテム」には、以前に受け取ったオブジェクトが含まれ、これらのアイテムが「moreItems」と呼ばれる新しく作成された配列に追加されます。いくつかのWebサービスからデータを収集していると想定しているので、connectionDidFinsihLoadingでこのステップを実装できます。

4)TableView / CollectionViewのデータソースを変更し、「moreItems」という新しい配列に置き換えます。

5)次の問題は、テーブルビュー全体をリロードしたくないので、新しいアイテムを処理したいということです。この機能を使用するには、アイテムを永続化する必要があります。アーカイブまたはコアデータは、使い慣れたものであれば何でも使用できます。

6)すでにフェッチされているアイテムは、アーカイブで言うと、それらを永続化する必要があります。また、ユーザーがアプリを開いたときに、ウェブサービスで更新されたアイテムをさらに取得しているときに、それらをテーブルビューに表示します。したがって、最初に永続化されたアイテムをすぐに表示してから、新しいアイテムを処理します。

7)いくつかの一意のオブジェクトを探す必要があります。私の場合は、すべてのアイテムに異なるリンクがあり、これに基づいて並べ替えて処理できるため、「リンク」でした。また、使用する必要があります

- (BOOL) isEqual:(id)object

Webサービス上のリンクとすでにテーブルビューにあるリンクを比較します。この手順が必要なのは、アプリがすでにテーブルビューにあるリンクを持つアイテムを追加しないためです。

8)各アイテムに関連付けられている日付がある場合は、その日付を使用してアイテムを並べ替え、「sortUsingComparator」を使用して新しいアイテムを一番上に表示できます。

9)また、「[[self tableView] insertRowsAtIndexPath:rows withRowAnimation:UITableViewRowAnimationTop」を使用して、新しいアイテムが以前のアイテムの上に追加されたことをユーザーに示す効果を持たせる必要があります。

お役に立てれば。

于 2013-01-16T22:31:01.753 に答える
3

テーブル全体をリロードしたくないのは、いくつかの項目を処理するよりもコストがかかるためです。

これは本当ですか?すべての単一のセルが画面に表示され、何百ものセルがあるという病的なケースがない限り、「効率的な」方法が「ブルートフォース」の方法よりも高速になるとは信じがたいです。

呼び出しreloadDataは、最終的に画面に表示されるセルを更新するようにデリゲートに要求するだけで、テーブル ビュー全体ですべてのセルを再作成することはありません。

ディメンションの計算の複雑さを変更するいくつかのメソッド ( などtableView:heightForRowAtIndexPath) を実装している場合、テーブル ビューはとにかくすべての高さを再計算する必要があるため、「効率的な」方法を使用してもメリットはありません。

あなたが探している解決策で問題が解決するかどうかはわかりませんが、私がひどく間違っていることを願っています.

于 2013-01-17T21:31:40.127 に答える
2

データ ソースに既に差分情報がある場合、UITableView reloadRowsAtIndexPaths:withRowAnimation:を使用すると、パフォーマンスが低下します。

于 2013-01-17T17:55:47.607 に答える