如果未删除其他对象的观察者,则KVO会导致循环 [英] KVO causes loop if observers to other objects are not removed

查看:152
本文介绍了如果未删除其他对象的观察者,则KVO会导致循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有观察员添加到几个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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆