通知观察者 - 绑定入门

时间:2011-06-19 21:15:56

标签: objective-c cocoa binding cocoa-bindings

为了开始使用绑定,我正在编写一个小应用程序,将摄氏温度转换为开尔文温度,反之亦然。

我有两个NSTextField绑定到两个属性float kelvinfloat centigrade。当然,我有两个自定义设置器,可以适当地设置每个属性的值。

摄氏的设定者是:

centigrade = value;
[self willChangeValueForKey:@"kelvin"];
kelvin = value + 273;
[self didChangeValueForKey:@"kelvin"];

我需要使用willChangeValueForKey:,否则该值不会在其他NSTextField中更新。

我的问题是,有更优雅的方法吗?如果我添加另一个属性和文本字段以将温度转换为华氏温度,我还需要在该getter中添加willChange...didChange...

有没有办法告诉nib文件这两个属性是否已链接,每当更改时,它必须通知两个观察者?

编辑:

为了它的价值,我尝试从centrigrade的二传手中调用开尔文的二传手。但是,如果我在开尔文的设定者中也这样做,它会不会引起问题?例如:

centigrade = value;
[self setKelvin:value];

kelvin = value;
[self setCelsius:value];

1 个答案:

答案 0 :(得分:2)

请勿在此处使用 willChangeValueForKey: / didChangeValueForKey:,通知是自动的。如果您没有看到通知,则表示您没有使用key-value coding compliant manner中的属性。您根本不需要自定义设置器。

你应该只调用willChangeValueForKey:/ didChangeValueForKey:如果你已经明确禁用了这些属性的自动kvo(有时会有这样的理由,但是保存它以便以后使用)。

一旦你有了工作,你就可以解决你的其他问题。是的,可以为两个属性都有一个属性更改触发器通知,但正如您所看到的,如果第二个属性更改也会再次触发第一个属性,则无效,依此类推。

问题是您的模型不够复杂,无法解决您的问题。忘记绑定一段时间,完全忘记演示文稿,直到模型正常工作。在伪代码中,忽略浮点细节,你需要至少得到这样的工作: -

model.celcius = 100.0;
assert( model.kelvin == 373.0 )

model.kelvin = 0.0;
assert( model.celcius == -273.0 )

假设您遵循kvo complience的指南(并了解何时使用它以及何时不使用 - 即,您可以控制何时触发通知),那么您将能够连接文本字段绑定和所有内容只会工作。

这可能类似于: -

@property (assign) float *temperatureKelvin;    // only one instance variable needed

- (float)temperatureFahrenheit {
  return tempeatureKelvin * ...;                // whatever formula is
}

- (float)temperatureCelcius {
  return tempeatureKelvin * ...;                // whatever formula is
}

- (void)setTemperatureFahrenheit:(float)val {
  self.temperatureKelvin = val * ...;           // whatever formula is
}

- (void)setTemperatureCelcius:(float)val { {
  self.temperatureKelvin = val * ...;           // whatever formula is
}

完成此工作的关键是确保更新temperatureKelvin的值会发送temperatureFahrenheit和temperatureCelcius已更改的通知。你可以通过将它们注册为依赖的preoperties来实现这一点。

+ (NSSet *)keyPathsForValuesAffectingTemperatureFahrenheit {
    return [NSSet setWithObject:@"tempeatureKelvin"];
}

+ (NSSet *)keyPathsForValuesAffectingTemperatureCelcius {
    return [NSSet setWithObject:@"tempeatureKelvin"];
}