Уведомление наблюдателя - Начало работы с привязками - PullRequest
1 голос
/ 20 июня 2011

Чтобы начать работу с привязками, я пишу небольшое приложение, которое преобразует температуру в градусах Цельсия в температуру в градусах Кельвина и наоборот.

У меня есть два поля NSTextFields, которые связаны с двумя свойствами, известными какfloat kelvin и float centigrade.И, конечно, у меня есть два пользовательских установщика, которые устанавливают значение для каждого свойства соответствующим образом.

Установщик для Цельсия:

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

Мне нужно использовать willChangeValueForKey:, иначе значениене обновляется в другом NSTextField.

Мой вопрос: есть ли более элегантный способ сделать это?Если я добавлю другое свойство и текстовое поле для преобразования температуры в градусы Фаренгейта, мне нужно будет также добавить willChange... и didChange... в этот геттер.

Есть ли способ сообщить файлу nib, что эти два свойствасвязаны, и всякий раз, когда кто-то изменяется, он должен уведомить обоих наблюдателей?

РЕДАКТИРОВАТЬ:

Для чего я пытался вызвать установщик Кельвина из установщика Сентраграда.Но если я сделаю это в установщике для кельвинов, разве это не вызовет проблем?Например:

centigrade = value;
[self setKelvin:value];

и

kelvin = value;
[self setCelsius:value];

1 Ответ

2 голосов
/ 20 июня 2011

Не использовать willChangeValueForKey: / didChangeValueForKey: здесь уведомления автоматически.Если вы не видите уведомлений, это означает, что вы не используете свойства в соответствии с кодировкой значения ключа .Вам вообще не нужны пользовательские сеттеры.

Вы должны только вызывать willChangeValueForKey: / didChangeValueForKey: если вы явно отключили автоматическое kvo для этих свойств (иногда есть причины сделать это, но сохраните это для дальнейшего использования).линия).

Если у вас есть такая работа, вы можете решить другую проблему.Да, для обоих свойств можно иметь одно уведомление о триггере изменения свойства, но, как вы видели, бесполезно, если второе изменение свойства также запускает первое снова и т. Д.

Проблема в том, что ваша Модель недостаточно развита, чтобы справиться с вашей проблемой.Забудьте о привязках на некоторое время, забудьте о презентации, пока модель не заработает.В псевдокоде, игнорируя детали с плавающей запятой, вам нужно по крайней мере получить что-то вроде этого: -

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"];
}
...