8

のにバインドされているNSViewサブクラスがありarrangedObjectsますNSArrayController。配列にアイテムが挿入または削除されると、ビューに通知されます。配列に格納されているモデルの属性が変更された場合に通知を受けるにはどうすればよいですか?

配列に追加されたすべてのアイテムのすべての (関連する) 属性にビューをオブザーバーとして追加する必要がありますか?

配列にアイテムが追加または削除されるobserveValueForKeyPath:ofObject:change:context:と、NSViewサブクラスで通知されます。配列に格納されているモデルへの変更は通知されませんが、挿入が通知されるたびに、ビューをオブザーバーとして新しいアイテムの属性に追加できます。これはこれを行うための最良の方法ですか?

何が起こるかを確認できるようにモデル クラスをオーバーライドし、適切な属性へのオブザーバーとして自分自身を追加する列にバインドされているaddObserverことに気付きました。これを自動的に行うことはできますか、それとも手動で監視を設定する必要がありますか?NSTableViewarrangedObjects

4

2 に答える 2

10

dreamlaxに大いに感謝しますが、私は自分の問題を説明するのに十分な仕事をしていなかったと思います。私のモデルクラスは監視可能であり、適切な通知を生成しましたが、配列内のすべてのアイテムを直接監視せずにそれらを監視する方法を理解することはできませんでした。

必要な非常に単純な変更を説明するものが見つからなかったため、キーパスのドキュメントを改善できると思います。配列の魔法のキーパスに関するいくつかの良い情報がありますが、単純な「これらは一般的なものです」というドキュメントはありません。

ともかく。以前、私のNSViewサブクラスには次のものがありました。

- (void) bind:(NSString *)binding toObject:(id)observable withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
{
  if ([binding isEqualToString:@"observedObjects"]) {
    [observable addObserver:self forKeyPath:@"arrangedObjects" options:0 context:nil];
  } else {
    [super bind:binding toObject:observable withKeyPath:keyPath options:options];
  }
}

NSArrayController内のモデルへの変更の通知を受け取るために追加する必要があるのは、 (モデルのプロパティの)arrangedObjects監視だけでした。したがって、上記のコードは次のようになります。arrangedObjects.namename

- (void) bind:(NSString *)binding toObject:(id)observable withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
{
  if ([binding isEqualToString:@"observedObjects"]) {
    [observable addObserver:self forKeyPath:@"arrangedObjects" options:0 context:nil];
    [observable addObserver:self forKeyPath:@"arrangedObjects.name" options:0 context:nil];
  } else {
    [super bind:binding toObject:observable withKeyPath:keyPath options:options];
  }
}

それでおしまい!これで、のオブジェクトarrangedObjectsname変更された場合に通知されます。

于 2009-06-10T10:58:56.933 に答える
3

潜在的に多くのキー値パスを監視するのではなく、何かが変更されたときに配列内の各オブジェクトに通知を投稿させないでください。1 つのオブジェクトが多くのキー値パスを監視するのではなく、1 つのオブジェクトだけが 1 つの通知を監視する必要があります。

編集:

また、配列されたオブジェクトは、+keyPathsForValuesAffecting<key>where <key>is your key name というクラス メソッドに応答することもできます。以下に例を示します:paymentDueは値invoiceItems.countまたはpaymentsMade変更されたときに影響を受けるキーです。invoiceItems.countまたはpaymentsMadeが変更されると、バインドされているものすべてに通知paymentDueが送信されます。

+ (NSSet *) keyPathsForValuesAffectingPaymentDue:
{
    return [NSSet setWithObjects:@"invoiceItems.count", @"paymentMade", nil];
}

10.4 で実行している場合、または 10.4 以前をターゲットにしている場合は、代わりにこの方法を使用する必要がありますが、基本的には同じことになります。

編集2:

あなたの他のコメントを明確にするために; 配列内の各オブジェクトを手動で呼び出すことができます

[[NSNotificationCenter defaultCenter] postNotificationName:@"ModelDidChange" object:self];

次に、いくつかのコントローラー コードを使用して、オブジェクトからの通知の更新を登録できます。一意の通知名を選択すると、特定のオブジェクトから手動でリッスンする必要がなくなり、NSNotificationCenter任意のオブジェクトからの通知を受け取るように に指示できます。コントローラーは、どのオブジェクトが変更されたかを非常に簡単に判断できます。

  1. 通知センターに登録します (これらのメソッドはコントローラー オブジェクトにある必要があります)。

    // This string could really be just about anything you want, but make it conspicuous.
    static NSString * const ModelDidChangeName = @"ModelDidChange";
    
    - (void) awakeFromNib
    {
        // using nil for the object parameter will make the notification center
        // invoke modelDidChange: regardless of who the sender is.
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(modelDidChange:) name:ModelDidChangeName object:nil];
    }
    
  2. 通知を処理するメソッドを実装します。

    - (void) modelDidChange:(NSNotification *) notification
    {
        MyModelClass *myObject = [notification object];
        // do stuff with your model if necessary.
        // do stuff with your view too
    }
    
  3. モデル オブジェクトの一部が変更されたときに通知を投稿するようにします。

    @implementation MyModelClass
    
    - (void) setSomething:(NSString *) newThing
    {
        [something autorelease];
        something = [newThing copy];
        if (something == nil)
        {
            // special case scenario for when something is nil
            // do stuff, modify MyModelClass instance's attributes
            [[NSNotificationCenter defaultCenter] postNotificationName:ModelDidChange object:self];
            // the controller's modelDidChange: method is automatically invoked.
        }
    }
    @end
    

しかし

モデルが適切に KVC に準拠し、適切な KVO コールバックで作成されている場合、手動通知は必要ありません。

于 2009-06-10T03:15:43.487 に答える