通知观察者 - 绑定入门

发布于 2024-11-16 05:14:09 字数 855 浏览 3 评论 0原文

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

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

celsius 的设置器是:

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

In order to get started with bindings, I'm writing a small application that converts temperature in Celsius to temperature in Kelvin and vice-versa.

I have two NSTextFields which are binded to two properties known as float kelvin and float centigrade. And, of course, I have two custom setters which set the value for each property appropriately.

The setter for celsius is:

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

I need to use willChangeValueForKey: otherwise the value is not updated in the other NSTextField.

My question is, is there a more elegant way to do this? If I add another property and textfield to convert the temperature to Fahrenheit, I will need to add willChange... and didChange... in that getter as well.

Is there a way to tell nib file that these two properties are linked and whenever one changes, it must notify both the observers?

EDIT:

For what its worth, I have tried calling the kelvin's setter from inside centrigrade's setter. But if I do that in the setter for kelvins as well, wouldn't it cause problems? For instance:

centigrade = value;
[self setKelvin:value];

and

kelvin = value;
[self setCelsius:value];

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

轮廓§ 2024-11-23 05:14:09

不要在此处使用 willChangeValueForKey: / didChangeValueForKey:,通知是自动的。如果您没有看到通知,则意味着您没有使用 键值编码兼容方式。您根本不需要自定义设置器。

如果您已明确禁用这些属性的自动 kvo,则应仅调用 willChangeValueForKey: / didChangeValueForKey: (有时有理由这样做,但请保存以供以后使用)。

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

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

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

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

假设您遵循 kvo 合规性指南(并了解何时使用它和何时不使用它 - 即,您可以控制何时使用它触发通知),然后您将能够连接文本字段绑定,一切都会正常工作。

这可能看起来像这样:-

@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
}

完成这项工作的关键是确保更新温度开尔文的值发送温度华氏度和温度摄氏度已更改的通知。您可以通过将它们注册为依赖预操作来完成此操作。

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

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

Don't use willChangeValueForKey: / didChangeValueForKey: here, the notifications are automatic. If you are not seeing the notifications it means you are not using the properties in a key-value coding compliant manner. You don't need custom setters at all.

You should only call willChangeValueForKey: / didChangeValueForKey: if you have explicitly disabled automatic kvo for those properties (there are sometimes reasons to do this, but save that for later down the line).

Once you have that working you can tackle your other problem. Yes, it is possible to have one property change trigger notifications for both properties, but as you have seen that is no use if the second property change also triggers the first again, and so on.

The problem is that your Model isn't sophisticated enough to deal with your problem. Forget bindings for a while, forget the presentation altogether until you have the model working. In pseudo-code, ignoring floating point details, you need to at least get something like this working:-

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

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

Assuming you follow the guides on kvo complience (and understand when to use it and when not to - ie, you are in control of when to trigger the notification), you will then be able to hook up your textfield bindings and everything will just work.

This might look something like:-

@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
}

The key to making this work is to make sure that updating the value of temperatureKelvin sends a notification that temperatureFahrenheit and temperatureCelcius have changed. You do this by registering them as dependant preoperties..

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

+ (NSSet *)keyPathsForValuesAffectingTemperatureCelcius {
    return [NSSet setWithObject:@"tempeatureKelvin"];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文