iOS如何删除同一对象上的多个观察者



当我开发KVO行为时,

[A addObserver:B forKeyPath:kLAShopRuleObserveKey options:NSKeyValueObservingOptionNew context:nil];

我删除了[B dealloc]中的观测者为:

[A removeObserver:B forKeyPath:kObserveKey];

它运行良好。

现在我多次添加观察者:

[A addObserver:B forKeyPath:kLAShopRuleObserveKey options:NSKeyValueObservingOptionNew context:nil];
[A addObserver:B forKeyPath:kLAShopRuleObserveKey options:NSKeyValueObservingOptionNew context:nil];

但我只在B:中删除了一次KVO

- (void)dealloc
{
[A removeObserver:self forKeyPath:kObserveKey];
}

它在iOS 11及更高版本上运行良好,但在iOS 10及更早版本上崩溃,的不同表现

在《键值观察编程指南:注册为观察者》中,他们指出应该使用context参数。

因此,定义您的上下文:

static void *observerContext = &observerContext;
static void *observerContext2 = &observerContext2;

然后在添加观察者时使用这些上下文:

[a addObserver:b forKeyPath:kLAShopRuleObserveKey options:NSKeyValueObservingOptionNew context:observerContext];
[a addObserver:b forKeyPath:kLAShopRuleObserveKey options:NSKeyValueObservingOptionNew context:observerContext2];

然后在移除观察者时使用这些上下文:

[a removeObserver:b forKeyPath:kLAShopRuleObserveKey context:observerContext];
[a removeObserver:b forKeyPath:kLAShopRuleObserveKey context:observerContext2];

这消除了任何歧义。它也应该工作,无论iOS版本如何。


顺便说一句,observeValueForKeyPath应该检查上下文参数,如果不匹配,则调用super格式副本。

例如,如果您有单独的处理程序:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == observerContext) {
// handle observer 1
} else if (context == observerContext2) {
// handle observer 2
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

或者,如果两者都在做同样的事情:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == observerContext || context == observerContext2) {
// handle observer
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

如果您的键恰好与某个超类使用的同一个键匹配,则此模式有助于避免可能出现的问题。

最新更新