web-dev-qa-db-ja.com

KVOとNSNotificationCenterを使用した可変配列への変更の監視

私のモデルには、イベントと呼ばれるオブジェクトの配列があります。新しいオブジェクトがイベントに追加されるたびにコントローラーに通知を受け取りたいのですが。

これを行う良い方法は、KVOパターンを使用して、イベントが変更されたときに通知を受け取ることだと思いました(新しいオブジェクトが追加されたことによる)

// AppDelegate
// events is a NSMutableArray @property/@synthesize etc...

[appDelagate addObserver:self
               forKeyPath:@"events"
                  options:NSKeyValueObservingOptionNew
                  context:NULL];

しかし、observeValueForKeyPathメソッドが呼び出されておらず、配列がKVOに準拠していないことがわかりました:

1つのオプションは、keyPathに対して---(willChangeValueForKeyを呼び出して、メソッドを手動でトリガーすることです。

// ViewController
[self willChangeValueForKey:@"events"];
[self.events addObject:event];
[self didChangeValueForKey:@"events"];

しかし、observeValueForKeyPathメソッドからアクセスできるように、イベント配列の前後の状態も追跡する必要があるため、これは重く感じます。

1つのアプローチは、(可変ではなく)標準配列を使用して、新しいオブジェクトを追加するたびにイベントの新しいインスタンスを作成/設定することです。または、アイテムの数を追跡する別のプロパティを作成することもできます。可変配列(@ "events.count"を監視できればいいのですが)。

別のオプションは、NSNotificationCenterを使用することです。ブロックの使用を提案するいくつかの回答も読みました(しかし、どこから始めればよいのかわかりません)。

最後に、コントローラーのインスタンスをデリゲートに保持して、関連するメッセージを送信することはできますか?

// Delegate
[myController eventsDidChange];

デリゲートからコントローラーへの参照を保持するのは奇妙ですか?

どちらを使用するのが最適かを選択する方法を理解するのに苦労しているので、パフォーマンス、将来のコードの柔軟性、およびベストプラクティスに関するアドバイスをいただければ幸いです。

19
MathewS

知らないうちに変更されないようにするために、変更可能なコレクションの直接のパブリックプロパティを作成しないでください。 NSArrayはそれ自体が観測可能なキー値ではありませんが、1対多プロパティ@"events"は観測可能です。これを観察する方法は次のとおりです。

まず、不変のコレクションのパブリックプロパティを宣言します。

@interface Model
@property (nonatomic, copy) NSArray *events;
@end

次に、実装で可変ivarを使用して戻します。

@interface Model ()
{
    NSMutableArray *_events;
}
@end

ゲッターとセッターをオーバーライドします。

@implementation Model

@synthesize events = _events;

- (NSArray *)events
{
    return [_events copy];
}

- (void)setEvents:(NSArray *)events
{
    if ([_events isEqualToArray:events] == NO)
    {
        _events = [events mutableCopy];
    }
}

@end

他のオブジェクトがモデルにイベントを追加する必要がある場合は、-[Model mutableArrayValueForKey:@"events"]を呼び出すことで変更可能なプロキシオブジェクトを取得できます。

NSMutableArray *events = [modelInstance mutableArrayValueForKey:@"events"];
[events addObject:newEvent];

これにより、毎回新しいコレクションでプロパティを設定することにより、KVO通知がトリガーされます。パフォーマンスを向上させ、よりきめ細かい制御を行うには、残りの 配列アクセサー を実装します。

参照: 挿入/削除のためのNSMutableArrayの監視

18
Ryder Mackay

アクセサメソッドに関するドキュメント に従って、以下を実装する必要があります。

- (void)addEventsObject:(Event*)e
{
    [_events addObject:e];
}

- (void)removeEventsObject:(Event*)e
{
    [_events removeObject:e];
}

その後、KVOは、これらが呼び出されたときに通知を発行します。

0
Bryan