4

KVO を使用して単一のオブジェクトのプロパティを観察しているビューがあります。ビュー内のオブジェクトのすべてのプロパティを観察しました。

[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL];
 [person addObserver:self forKeyPath:@"photo" options:NSKeyValueObservingOptionNew context:NULL];
 [person addObserver:self forKeyPath:@"address" options:NSKeyValueObservingOptionNew context:NULL];

現在、1 つのプロパティだけが変更された場合は問題ないように見えますが、オブジェクト全体が変更された場合、わずか数秒で通知が 3/4 回トリガーされます。変更に基づいてネットワークからデータをロードする必要があります。1 つのプロパティを変更すると 1 つのネットワーク リクエストが作成されますが、複数のプロパティが同時に変更された場合。同じオブジェクトのリクエストのキューを作成します。これは、いくつかの問題につながります。複数のプロパティを同時に監視し、すべてのプロパティが変更された場合でも 1 回だけロードするにはどうすればよいですか。私を助けてください。これは深刻なトラブルです。

4

1 に答える 1

6

Grand Central Dispatchのディスパッチソースを使用して、プロパティ変更の観測を合体させ、処理できるよりも頻繁に発生しないようにすることができます。

@implementation Controller
{
    dispatch_source_t source;
}
- (id)init
{
    self = [super init];
    if (self)
    {
        //We are using data add source type, but not actually using the added data.
        source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue());
        dispatch_source_set_event_handler(source, ^{
            //Insert your network call to load data from the network.
            //The event handler will only be called when another event handler is not being processed. So you won't attempt to do another network call until the last call was completed.

        });
        //Dispatch sources always start out suspended so you can add the event handler. You must resume them after creating them if you want events to be delivered)
        dispatch_resume(source);
    }
    return self;
}
- (void)dealloc
{
    dispatch_release(source);
}
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    //Tell dispatch source some data changed. It will only call the event handler if an event is not currently being handled.
    //You could add a custom timer based coalesce here for when no events are currently being processed if you want to delay all initial events to potentially wait for more changes 
    dispatch_source_merge_data(source, 1);
}
@end

したがって、最初のプロパティ変更通知は、ディスパッチソースイベントハンドラーをトリガーします。既存のイベントの実行中に発生する後続のプロパティ変更は、最後のイベントが完了するとすぐに実行されるようにキューに入れられます。つまり、5つのプロパティがすばやく連続して変更されると、(5つのネットワーク呼び出しではなく)2つのネットワーク呼び出しが発生します。2番目のネットワーク呼び出しを排除するために通知への即時の応答性を犠牲にしたい場合は、イベントが処理されていないときにカスタムタイマーベースの合体を追加できます。

于 2013-01-23T19:43:36.480 に答える