0

配列コントローラー (辞書の配列を管理する) にバインドされた NSTableView を使用して、単純なインターフェイスを初期化しています。バックグラウンドで配列のコンテンツを読み込み (非常に時間のかかるプロセスです)、100 または 1000 要素ごとにテーブル ビューを更新したいと考えています。アイデアは、インターフェイスが利用可能で応答性が高いということです。後で更新/更新をトリガーする方法もわかりません。テーブルは空のままです。誰でもポインタを提供できますか?

私の現在のアプローチは次のとおりです。

// In init for my app controller. This seems to work well, but I've tried other methods here.
[self performSelectorInBackground:@selector(loadTable) withObject:nil];


- (void)loadTable {
  tracks = [[NSMutableArray alloc] initWithCapacity:[masters count]];

  // ... create each object one-by-one. Add it to tracks.
  for (... in ...) {
    [tracks addObject:newObject];
  }

  // Now I don't know what to do next. The table remains empty. 
  // Things I've tried (though possibly not in all combinations with the
  // method above):
  // 1. With a suitably-defined reloadData method, which just reloads
  //   the table view and sets needs display.
  [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];

  // 2. Reload directly.
  [tv reloadData];
  [tv setNeedsDisplay];
}

データを直接ロードするだけで、バックグラウンドでそれを実行しようとしない場合、すべて正常に動作しますが、ほぼ 30 秒かかります。

4

2 に答える 2

6

配列コントローラーにバインドされたテーブル列 (私はあなたが意図したと思います) を持っているので、そこからテーブル ビューがデータを取得します。テーブル ビューは更新された配列を要求している可能性が非常に高いですが、何も変更されていないことを認識していない配列コントローラーに要求しています。

アレイ コントローラは、単に向きを変えて新しいデータを要求するだけではありません。これは、テーブル ビューを配列にバインドするのを難しくするためだけに存在することを意味しますが、そうではありません。これはコントローラーです。その仕事は、配列 (のコピー) を所有し、その順序と、そのオブジェクトのサブセットのユーザーの選択を維持することです。

したがって、配列にアイテムをいつ追加するかを確認するには、配列コントローラーが必要です。これを実現する最善の方法は、アレイ コントローラーcontentArrayをコントローラーのプロパティにバインドし、そのプロパティを KVO 準拠の方法で更新することです。

つまり、次のことを意味します。

  1. メソッドで可変配列を作成しますinit。(もちろん、 でリリースしdeallocます。)
  2. 便宜上、配列アクセサー メソッド、 plus addTracksObject:、および(これらは技術的に設定されたアクセサー メソッドであるため、KVO は配列プロパティに対してそれらを無視します) を実装removeTracksObject:します。
  3. トラックを追加するには、自分自身にaddTracksObject:メッセージを送信してください。insertObject:inTracksAtIndex:自分自身にメッセージを送信してそれに応答する必要があります ( [self countOfTracks]insort を実行する場合を除き、インデックスに対して)。また、配列にメッセージinsertObject:inTracksAtIndex:を送信して応答する必要があります。tracksinsertObject:atIndex:

前述したように、KVO は NSArray プロパティを無視addFooObject:removeFooObject:fooこれらの NSSet プロパティ アクセサーのみを考慮します。これら配列アクセサーであるため、それらの上insertObject:inFooAtIndex:に実装する必要があります。つまり、KVO はそれらに反応します。removeObjectFromFooAtIndex:

先ほど説明したように、ステップ 3 は非常に遅くなります。これは、配列コントローラーがプロパティを再フェッチし、テーブル ビューが、arrangedObjects追加する行ごとに少なくとも 1 回は配列コントローラーのプロパティを再フェッチするためです。

したがって、次の代替手順 3 でバッチ追加動作を維持する必要があります。

  • を実装insertTracks:atIndexes:し、トラックの 1 つのバッチ (たとえば、100 または 1000) の配列と によって形成されたインデックス セットを渡します[NSIndexSet indexSetWithRange:(NSRange){ [self countOfTracks], countOfBatch }]removeTracksAtIndexes:また、対応するメソッドがない場合、KVO は各挿入メソッドを無視するため、も実装する必要があります。

行を取り込んでいる間にユーザーを過度にイライラさせないように、選択を保持するように配列コントローラーを設定する必要があります。

また、バックグラウンド スレッドでオブジェクトを作成し、メイン スレッドの実行を使用して追加する別のバッチを定期的に送信することもできます。私は通常、可能な限りメイン スレッドの実行ループで処理を行うことを推奨していますが、この種の処理を行うと、定期的な負荷が別のバッチを構築している間、インターフェイスが簡単に遅延する可能性があります。

于 2010-11-22T06:45:51.377 に答える
1

setNeedsDisplay:YESメインスレッドでテーブルビューを呼び出す必要があります。バックグラウンド スレッドから呼び出さないでください。すべての Cocoa UI 呼び出しは、メイン スレッドで実行する必要があります。そうしないと、おかしなことが起こります。

于 2010-11-22T07:26:54.070 に答える