如果未删除其他对象的观察者,则KVO会导致循环 [英] KVO causes loop if observers to other objects are not removed
问题描述
我有观察员添加到几个NSTextFields来监视每个文本字段中的更改。每个文本字段的键在Interface Builder中配置 Bindings - >值 - >模型键路径
。当一个文本字段中的数字更改时,其他文本字段自动更新其值。因为观察者被添加到每个文本字段,我必须删除其他观察者,以避免循环,将会崩溃的应用程序。在删除观察者后,我必须将它们添加回其他文本字段,以便可以监视用户的输入。我的方法是工作正常,但我可以看到如果添加了很多观察者这可以是繁琐的。
I have observers added to several NSTextFields to monitor changes in each text field. The key of each text field is configured in Interface Builder at Bindings -> Value -> Model Key Path
. When the number in one text field is changed, the other text fields automatically update their value. Since an observer was added to each text field, I must remove the other observers to avoid a loop that will crash the app. After the observers are removed, I must add them back to the other text fields so they can be monitored for input by the user. My approach is working fine, but I can see how this can be cumbersome if a lot of observers are added.
有一种方法来简化这个,根据用户的输入,必须添加和删除观察者吗?
Is there a way to streamline this to where I don't have to add and remove observers depending on the user's input?
#import "Converter.h"
@interface Converter ()
@property double kilometer, mile, foot;
@end
@implementation Converter
- (void)awakeFromNib {
[self addObserver:self forKeyPath:@"kilometer" options:0 context:nil];
[self addObserver:self forKeyPath:@"mile" options:0 context:nil];
[self addObserver:self forKeyPath:@"foot" options:0 context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"kilometer"]) {
[self removeObserver:self forKeyPath:@"mile"];
[self removeObserver:self forKeyPath:@"foot"];
NSLog(@"kilometers");
[self setMile: [self kilometer] * 0.62137119 ];
[self setFoot: [self kilometer] * 3280.8399 ];
[self addObserver:self forKeyPath:@"mile" options:0 context:nil];
[self addObserver:self forKeyPath:@"foot" options:0 context:nil];
}
if ([keyPath isEqualToString:@"mile"]) {
[self removeObserver:self forKeyPath:@"kilometer"];
[self removeObserver:self forKeyPath:@"foot"];
NSLog(@"miles");
[self setKilometer: [self mile] * 1.609344 ];
[self setFoot: [self mile] * 5280 ];
[self addObserver:self forKeyPath:@"kilometer" options:0 context:nil];
[self addObserver:self forKeyPath:@"foot" options:0 context:nil];
}
if ([keyPath isEqualToString:@"foot"]) {
[self removeObserver:self forKeyPath:@"kilometer"];
[self removeObserver:self forKeyPath:@"mile"];
NSLog(@"feet");
[self setKilometer: [self foot] * 0.0003048 ];
[self setMile: [self foot] * 0.00018939394 ];
[self addObserver:self forKeyPath:@"kilometer" options:0 context:nil];
[self addObserver:self forKeyPath:@"mile" options:0 context:nil];
}
}
@end
用户界面的屏幕截图:
Here's a screen shot of the user interface:
为了帮助澄清代码在做什么(或假设要做的事情):
To help clarify what the code is doing (or suppose to be doing):
用户希望将英尺转换为公里和英里,在英尺文本字段中输入一个值。使用适当的转换因子。
User wants to convert feet to kilometer and miles, so he inputs a value into the feet text field. The appropriate conversion factors are used.
用户希望将公里换算为英里和英尺,因此他在公里字段中输入一个值。使用不同的转换因子集。
The user wants to convert kilometers to miles and feet, so he inputs a value into the kilometer field. A different set of conversion factors are used.
等...
推荐答案
通过自定义您的setter方法并实现 +(BOOL)automaticallyNotifiesObserversForKey:
,您可以以嵌套方式手动更新这些属性的通知。
By customizing your setter method and implementing + (BOOL)automaticallyNotifiesObserversForKey:
, you can manually update notifications for these properties in a nested way.
以下代码经过测试可以正常工作。 (注意,我没有使用你的系数和属性名称)。
The following codes are tested to be working. (Note that I did not use your coefficients and property names).
#define BEGIN_UPDATE [self willChangeValueForKey:@"m"];\
[self willChangeValueForKey:@"km"];\
[self willChangeValueForKey:@"f"];
#define END_UPDATE [self didChangeValueForKey:@"f"];\
[self didChangeValueForKey:@"km"];\
[self didChangeValueForKey:@"m"];
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
if ([key isEqualToString:@"f"]||[key isEqualToString:@"km"]||[key isEqualToString:@"m"]) {
return NO;
}
return [super automaticallyNotifiesObserversForKey:key];
}
- (void)setF:(float)f {
BEGIN_UPDATE
_m = 0.5*f;
_km = 0.1*f;
_f = f;
END_UPDATE
}
- (void)setKm:(float)km {
BEGIN_UPDATE
_km = km;
_f = 10*km;
_m = 5*km;
END_UPDATE
}
- (void)setM:(float)m {
BEGIN_UPDATE
_m = m;
_km = 0.2*m;
_f = 2*m;
END_UPDATE
}
这篇关于如果未删除其他对象的观察者,则KVO会导致循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!