5

基になる配列を更新するメソッドが呼び出されたときに、NSArrayController にバインドされた tableView を更新するにはどうすればよいですか? 例はこれを明確にするかもしれません。

アプリケーションが起動すると、SubwayTrain が作成されます。SubwayTrain が初期化されると、単一の SubwayCar が作成されます。SubwayCar には可変配列「passengers」があります。地下鉄の車両が初期化されると、乗客の配列が作成され、いくつかの People オブジェクトが配置されます (「切符売り場」という名前の人と「ホームレスの男性」という名前の別の人を考えてみましょう)。これらの人は常に SubwayCar に乗っているので、初期化時にそれらを作成し、乗客配列に追加します。

アプリケーションの存続期間中、人々は車に乗り込みます。「addPassenger」は SubwayCar で呼び出され、人が引数として渡されます。

私は、subwayTrain.subwayCar.passengers にバインドされた NSArrayController を持っており、起動時に私のチケット コレクターとホームレスの男性が正常に表示されます。しかし、[subwayCar addPassenger:] を使用すると、tableView が更新されません。乗客が確実に配列に追加されていることを確認しましたが、GUI では何も更新されません。

私は何を間違っている可能性がありますか?私の本能は、それがKVOに関連しているということです-配列コントローラーは、addPassengerが呼び出されたときに更新することを知りません(addPassengerが[passengers addObject:]を呼び出しても)。

喜んで手伝ってくれる人に感謝します。

アップデート

したがって、addPassenger メソッドを

[seatedPlayers addObject:person];

NSMutableSet *newSeatedPlayers = [NSMutableSet setWithSet:seatedPlayers];

[newSeatedPlayers addObject:sp];

[seatedPlayers release];

[self setSeatedPlayers:newSeatedPlayers];

これは、[self setSeatedPlayers] を使用しているためだと思います。これは正しい方法ですか?配列をコピーし、古い配列を解放し、コピーを更新するのは (既存の配列に追加するだけではなく) 非常に面倒に思えます。

4

5 に答える 5

7

バグと見なされるかどうかはわかりませんが、addObject: (および removeObject:atIndex:) は KVO 通知を生成しないため、アレイ コントローラー/テーブル ビューが更新されません。KVO に準拠するには、mutableArrayValueForKey を使用します。

例:

[[self mutableArrayValueForKey:@"seatedPlayers"] addObject:person];

また、insertObject:inSeatedPlayersAtIndex: も実装する必要があります。これは、デフォルトの KVO メソッドが非常に遅いためです (まったく新しい配列を作成し、その配列にオブジェクトを追加し、元の配列を新しい配列に設定するため、非常に非効率的です)。

- (void)insertObject:(id)object inSeatedPlayerAtIndex:(int)index
{
   [seatedPlayers insertObject:object atIndex:index];
}

このメソッドは、配列コントローラーがオブジェクトを追加するときにも呼び出されることに注意してください。そのため、元に戻す操作の登録などを考えるための優れたフックでもあります。

于 2010-01-15T07:41:22.933 に答える
2

私はこれを試していないので、うまくいくとは言えませんが、電話してKVO通知を受け取ることはありませんか

insertObject:atArrangedObjectIndex:

ArrayController で?

于 2010-01-15T20:12:46.250 に答える
1

Key Value Observingの魔法の鍵はKey Value Complianceにあります。最初はメソッド名 addObject: を使用していましたが、これは「順序付けられていないアクセサー パターン」にのみ関連付けられており、プロパティはインデックス付きプロパティ (NSMutableArray) でした。プロパティを順序付けされていないプロパティ(NSMutableSet)に変更すると、機能しました。NSArray または NSMutableArray はインデックス付きプロパティであり、NSSet または NSMutableSet は順序付けされていないプロパティであると考えてください。このセクションを注意深く読んで、魔法を実現するために何が必要かを理解する必要があります... Key-Value-Compliance . 使用する予定がない場合でも、さまざまなカテゴリに「必須」のメソッドがいくつかあります。

于 2012-12-23T21:27:53.313 に答える
1

したがって、addPassenger メソッドを

[seatedPlayers addObject:person];

NSMutableSet *newSeatedPlayers = [NSMutableSet setWithSet:seatedPlayers];
[newSeatedPlayers addObject:sp];
[seatedPlayers release];
[self setSeatedPlayers:newSeatedPlayers];

を使っているからだと思います[self setSeatedPlayers]。これは正しい方法ですか?

まずsetSeatedPlayers:、コロン付きの です。これは、Objective-C では非常に重要です。

独自のセッターを使用するのは正しい方法ですが、間違った正しい方法を使用しています。それは機能しますが、必要以上のコードをまだ書いています。

あなたがすべきことは、 などの set アクセサーを実装することですaddSeatedPlayersObject:。次に、そのメッセージを自分に送信します。これにより、人を追加するのは短いワンライナーになります。

[self addSeatedPlayersObject:person];

また、KVC 準拠のアクセサー形式に従っている限り、KVO 通知を無料で受け取ることができますsetSeatedPlayers:

これの利点は次のsetSeatedPlayers:とおりです。

  • セットを変更するコードは短くなります。
  • 短いのですっきりします。
  • 特定の set-mutation アクセサーを使用すると、一般的な the-dang-set-changed 通知ではなく、特定の set-mutation KVO 通知の可能性が提供されます。

mutableSetValueForKey:また、簡潔にするためと、その文字列リテラルのキーのスペルを間違えやすいため、よりもこのソリューションを好みます。( Uli Kusterer には、それが発生したときに警告を発生させるマクロがあります。これは、KVC または KVO 自体と対話する必要がある場合に役立ちます。)

于 2010-01-17T02:42:04.867 に答える
0
  1. 変更によって KVO 通知が発生しないように見える場合は、メンバーの変更を使用willChangeValueForKey:してラップします。didChangeValueForKey:これは、インスタンス変数を直接変更する場合に便利です。

  2. 変更によって KVO 通知が発生しないように見える場合は、コレクションのコンテンツの変更を使用willChangeValueForKey:withSetMutation:usingObjects:してラップします。didChangeValueForKey:withSetMutation:usingObjects:

  3. [seatedPlayers setByAddingObject:sp]物事を短くし、変更可能なセットを不必要に割り当てることを避けるために使用します。

全体として、次のいずれかを行います。

[self willChangeValueForKey:@"seatedPlayers"
            withSetMutation:NSKeyValueUnionSetMutation 
               usingObjects:sp];
[seatedPlayers addObject:sp];
[self didChangeValueForKey:@"seatedPlayers" 
           withSetMutation:NSKeyValueUnionSetMutation 
              usingObjects:sp];

またはこれ:

[self setSeatedPlayers:[seatedPlayers setByAddingObject:sp]];

後者の代替手段では、1 にリストされている関数が自動的に呼び出されます。最初の代替手段のほうがパフォーマンスが向上します。

于 2012-02-14T17:08:00.150 に答える