2011-06-19 1 views
1

Pour commencer avec les liaisons, j'écris une petite application qui convertit la température en degrés Celsius en température en Kelvin et vice-versa.Notifier un observateur - Premiers pas avec les liaisons

J'ai deux NSTextFields qui sont liés à deux propriétés connues comme float kelvin et float centigrade. Et, bien sûr, j'ai deux setters personnalisés qui définissent la valeur de chaque propriété de manière appropriée.

Le poseur de celsius est:

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

-je utiliser willChangeValueForKey: sinon la valeur est pas mis à jour dans l'autre NSTextField.

Ma question est, y at-il une façon plus élégante de faire cela? Si j'ajoute une autre propriété et textfield pour convertir la température en Fahrenheit, je devrais ajouter willChange... et didChange... dans ce getter aussi bien.

Y at-il un moyen de dire au fichier nib que ces deux propriétés sont liées et chaque fois que l'on change, il doit en aviser les deux observateurs?

EDIT:

Pour ce que ça vaut, je l'ai essayé d'appeler le poseur de kelvin à l'intérieur du poseur de centigrades. Mais si je fais cela aussi dans le setter pour kelvins, cela ne causerait-il pas de problèmes? Par exemple:

centigrade = value; 
[self setKelvin:value]; 

et

kelvin = value; 
[self setCelsius:value]; 

Répondre

2

Ne pas utiliser willChangeValueForKey:/didChangeValueForKey: ici, les notifications sont automatiques. Si vous ne voyez pas les notifications, cela signifie que vous n'utilisez pas les propriétés dans un key-value coding compliant manner. Vous n'avez pas besoin de setters personnalisés du tout.

Vous ne devez appeler que willChangeValueForKey:/didChangeValueForKey: si vous avez explicitement désactivé kvo automatique pour ces propriétés (il y a parfois des raisons de le faire, mais sauvegardez cela pour plus tard sur la ligne).

Une fois que vous avez ce travail, vous pouvez résoudre votre autre problème. Oui, il est possible d'avoir une propriété qui modifie les notifications de déclenchement pour les deux propriétés, mais comme vous l'avez vu, cela ne sert à rien si la seconde modification de propriété déclenche à nouveau la première, et ainsi de suite.

Le problème est que votre modèle n'est pas assez sophistiqué pour faire face à votre problème. Oubliez les reliures pendant un moment, oubliez complètement la présentation jusqu'à ce que le modèle fonctionne. En pseudo-code, en ignorant les détails de virgule flottante, vous devez au moins obtenir quelque chose comme ce travail: -

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

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

En supposant que vous suivez les guides sur KVO complience (et comprendre quand l'utiliser et quand ne pas - à savoir , vous êtes en contrôle du moment où déclencher la notification), vous serez alors en mesure de brancher vos liaisons de champs de texte et tout fonctionnera.

Cela pourrait ressembler à: -

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

La clé de ce travail est de faire en sorte que la mise à jour de la valeur de temperatureKelvin envoie une notification temperatureFahrenheit et temperatureCelcius ont changé. Vous faites cela en les enregistrant comme préopératoires dépendantes.

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

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

Je me sentais complètement hors de propos. Je devine que je dois rendre mon modèle KVO conforme et juste avoir deux propriétés de flotteur ne va pas le couper? De plus, vous déclarez que je n'ai pas du tout besoin de setters personnalisés - n'aurai-je pas besoin de code pour convertir les kelvins en celsius et vice-versa? – saad

+0

Je viens aussi de surcharger + keyPathsForValuesAffectingValueForKey et cela semble fonctionner aussi bien. Mais je tiens toujours à ce que vous avez dit sur le modèle. FWIW, j'ai un modèle primitif mais si je supprime les accesseurs personnalisés cela ne change évidemment pas la température mais les valeurs mais les setters/getters synthétisés sont encore appelés ofcourse et les valeurs sont mises à jour. J'ai confirmé en connectant deux champs de texte à la même propriété et en changeant l'un met à jour l'autre. – saad

+0

J'ai ajouté un peu plus d'explications. Le point sur le modèle n'est pas vraiment que vous avez besoin d'un modèle complexe, juste qu'il est bon de le développer indépendamment de vos vues, de préférence avec des tests unitaires :) – hooleyhoop