KVO/KVC
berfis
Membre
Bonjour tout le monde,
J'ai deux propriétés distinctes, j'aimerais que l'une soit mise à jour par l'autre, mais pas l'inverse.
Je m'explique: j'ai des préférences d'application et des préférences de document. Quand l'utilisateur ouvre un nouveau document, les préférences de celui-ci sont réglées sur celles de l'application, mais il est libre de les changer par la suite. Mais si les préférences de l'application changent, celles du document doivent changer aussi -- ainsi que dans les futurs documents.
Les préférences de l'application vont persister via le Shared User Controller, celles du document seront enregistrées avec le document.
Bref. Ce qui je veux, c'est visiblement un Observer (les propriétés du document vont "observer" celles de l'application). Questions:
1. Si un textField contenant une préférence d'application est modifié par l'utilisateur, est-ce qu'un autre textField contenant une préférence de document va voir son contenu changer également? (les deux textFields sont liés par "value" à une propriété différente)
2. L'observation n'a pas lieu dans le sens contraire?
Merci de vos éclaircissements bienvenus!
J'ai deux propriétés distinctes, j'aimerais que l'une soit mise à jour par l'autre, mais pas l'inverse.
Je m'explique: j'ai des préférences d'application et des préférences de document. Quand l'utilisateur ouvre un nouveau document, les préférences de celui-ci sont réglées sur celles de l'application, mais il est libre de les changer par la suite. Mais si les préférences de l'application changent, celles du document doivent changer aussi -- ainsi que dans les futurs documents.
Les préférences de l'application vont persister via le Shared User Controller, celles du document seront enregistrées avec le document.
Bref. Ce qui je veux, c'est visiblement un Observer (les propriétés du document vont "observer" celles de l'application). Questions:
1. Si un textField contenant une préférence d'application est modifié par l'utilisateur, est-ce qu'un autre textField contenant une préférence de document va voir son contenu changer également? (les deux textFields sont liés par "value" à une propriété différente)
2. L'observation n'a pas lieu dans le sens contraire?
Merci de vos éclaircissements bienvenus!
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
- lorsque qu'une pref de l'appli change, une notification est envoyée
- à l'ouverture, chaque document s'enregistre pour recevoir cette notif.
[notifCenter addObserver:self selector:@monSelecteur name:@MaVariableAChangeobject:maProprieteApplication];
?
Bon, si c'est en interne dans ton appli, les NSNotification suffisent, sinon ce sont les NSDistributedNotifications.
Les classes qui doivent réagir aux notifications implémentent un écouteur de type :
En général, les écouteurs sont dans une méthode appelée lors de l'initialisation
Ta void est de type :
- (void) laVoidQuiVaReagir:(NSNotification) notification;
La classe qui émet la notification le fait avec :
On peut même y adjoindre un NSDictionnary... (enfin, dans les interApp, en interne je n'ai jamais eu besoin)
Mon synthé Dazibao est truffé de notifications pour que les graphiques commandent l'audio. Cela remplace les vieux jacks... (c'est marrant, Google rend hommage à Moog aujourd'hui...)
Utiliser NSNotificationCenter est une possibilité, mais qui va émettre les notifications ? Tu ne pourras plus binder les préférences sur le Shared Defaults Controller, il te faudra un contrôleur intermédiaire pour pouvoir intercepter les changements de préférences et émettre la notification.
Et puis, les notifications sont en général une mauvaise idée, parce que 1) elles sont globales et 2) elle sont identifiées par des chaà®nes. Si tu utilises un objet intermédiaire, autant utiliser le design pattern Délégation: les appels de méthodes seront ciblés vers un seul objet, et vérifiés à la compilation.
(NSCoding, NSDictionary, @property, etc.)
Cette idée simple dépasse les possibilités de la simple assignation de mémoire de C d'une façon étonnante!
Mais lorsque j'essaie d'observer mon USD Controller, que dalle. J'écris ceci:
J'obtiens cela:
2012-05-25 15:49:17.694 null[12864:403] [<NSTextField 0x7fec3b10a1e0> addObserver:<NSUserDefaultsController 0x7fec3b111ca0> forKeyPath:@values.from options:0x3e7 context:0x0] was sent to an object that is not KVC-compliant for the "values" property.
... et donc mon "Observer"... n'observe rien.
Où ai-je fauté?
Deuxièmement, je te confirme que NSTextField n'a pas de propriété "values".
Là , la console commence à déborder. Donc l'idée c'était, grâce à "ce mécanisme merveilleux et si simple" que le text field "toData" se mette à jour quand la valeur "from" du contrôleur était modifiée dans un autre text field.
Où est (où sont) la (les) bourde(s)?
1. D'abord la méthode pour répondre aux notifications n'est pas didChangeValueForKey mais celle-ci...
2. J'observe une propriété du sharedUserDefaultsController. C'est un contrôleur de dictionnaire. Imaginons que l'utilisateur raye d'un trait de "backspace" le contenu du champ observé. Que devient le key path? Comme il n'est plus lié à rien, le contrôleur supprime la clé. Ensuite j'essaie de mettre le champ observateur à jour. Et qu'est-ce que je lui envoie dans son setStringValue? Un joli NIL bien dodu... KVO n'apprécie pas du tout, inonde la console et se met en grève.
Voila pourquoi je dois tester if([udc valueForKeyPath:keyPath]) avant de mettre à jour, sinon: ticket pour la quatrième dimension...
Les bindings, j'ai trouvé ça génial dès le début (cà d en ApplescriptObjC il y a un an). C'est une approche plutôt IB. Là je découvre KVO/KVC, c'est une approche codée (en l'occurrence bourrée de IF assez moches). Ca ouvre des horizons, mais ce n'est pas évident au début...
En tous les cas, merci pour les coups de mains et les avis.