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];

现在,当只有一个属性发生变化时,这似乎很好,但是当整个对象发生变化时,通知会在几分之一秒内被触发 3/4 次。我需要根据更改从网络加载数据。虽然单个属性更改会创建单个网络请求,但如果同时更改多个属性。它为同一对象创建一个请求队列。这会导致一些问题。即使所有属性都发生了变化,如何同时观察多个属性并且只加载一次。请帮帮我。这是一个严重的麻烦,我已经陷入困境。

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 个属性快速连续更改,您将获得 2 个网络调用(而不是 5 个网络调用)。如果您希望牺牲对通知的即时响应以消除第二次网络调用,则可以在未处理任何事件时添加基于自定义计时器的合并。

于 2013-01-23T19:43:36.480 回答