[Bindings]VLCKit, révélateur de mon incompréhension coriace aux Bindings
Omfraax
Membre
Bonjour à tous,
Je me suis mis aux Bindings il ya quelques semaines déjà et il me semble que je comprends (ou du moins j'arrive à les faire marcher) de plus en plus mais j'arrive à un nouveau point de blocage.
Depuis que VLC a sorti le VLCKit, je m'en sert de prétexte pour me faire un peu la main et voilà le problème.
Il y a une classe VLCMediaPlayer qui possède une variable de type VLCTime et deux beaux accessors :
Ensuite, dans le fichier VLCTime.h, on trouve la property suivante
Voilà pour le VLCKit...
Ensuite, j'ai fabriqué une classe Root qui contient essentiellement ça (avec bien sûr des méthodes du genre play et un Outlet sur une View pour afficher la vidéo mais là n'est pas le problème)
Dans l'interface, j'ai un NSTextField dont je veux qu'il affiche ce fameux time, si possible avec des Bindings pour la beauté du geste.
Pour commencer j'y vais cool, je remarque déjà que VLCMediaPlayer envoie à son delegate un message
Donc j'appelle à l'initialisation un petit
pour être notifié.
Je modifie ma classe root pour y rajouter une nouvelle property
Et enfin, j'implémente mediaPlayerTimeChanged :
et enfin je binde le NSTextField de mon interface avec la key timeValue, via un ObjectController de IB.
Et là , tout marche bien !!
Mais je me dis que c'est bête d'avoir créé une variable timeValue quand on fait des bindings surtout que les classes VLCMediaPlayer et VLCTime m'ont l'air d'être KVC-compliantes.
Je teste en faisant provisoirement de mon objet Root un Observer pour la clé time que la mise à jour de cette variable renvoie bien des notifications KVO--> tout est OK.
Puis je basarde ma variable timeValue, l'implémentation de la méthode mediaTimeChanged et je fais de ma variable myPlayer une property :
Enfin je binde directement mon NSTextField à la key myPlayer.time.stringValue.
Et là patatras, il ya le Null placeHolder dans mon NSTextField au lieu de l'affichage escompté...
Qu'est ce qui ne va pas ?
Si aussi vous voyez des maladresses (par exemple, je suis pas très l'aise sur la necessité de déclarer les variables comme @property pour pouvoir les binder ...), n'hésitez pas !
Merci d'avance pour votre aide.
Je me suis mis aux Bindings il ya quelques semaines déjà et il me semble que je comprends (ou du moins j'arrive à les faire marcher) de plus en plus mais j'arrive à un nouveau point de blocage.
Depuis que VLC a sorti le VLCKit, je m'en sert de prétexte pour me faire un peu la main et voilà le problème.
Il y a une classe VLCMediaPlayer qui possède une variable de type VLCTime et deux beaux accessors :
<br />- (void)setTime:(VLCTime *)value;<br />-(VLCTime *)time;<br />
Ensuite, dans le fichier VLCTime.h, on trouve la property suivante
<br />@property (readonly) NSString * stringValue;<br />
Voilà pour le VLCKit...
Ensuite, j'ai fabriqué une classe Root qui contient essentiellement ça (avec bien sûr des méthodes du genre play et un Outlet sur une View pour afficher la vidéo mais là n'est pas le problème)
<br />@interface Root : NSObject {<br /> <br /> VLCMediaPlayer* myPlayer;<br />}<br />
Dans l'interface, j'ai un NSTextField dont je veux qu'il affiche ce fameux time, si possible avec des Bindings pour la beauté du geste.
Pour commencer j'y vais cool, je remarque déjà que VLCMediaPlayer envoie à son delegate un message
<br />- (void)mediaPlayerTimeChanged:(NSNotification *)aNotification;<br />
Donc j'appelle à l'initialisation un petit
<br />[myPlayer setDelegate:self];<br />
pour être notifié.
Je modifie ma classe root pour y rajouter une nouvelle property
<br />@interface Root {<br />....<br />NSMutableString *timeValue;<br />}<br />...<br />@property(retain) NSString *timeValue;<br />...<br />@end<br />
Et enfin, j'implémente mediaPlayerTimeChanged :
<br />- (void)mediaPlayerTimeChanged:(NSNotification *)aNotification {<br /> [self setValue:[[myPlayer time] stringValue] forKey:@"timeValue"]<br />}<br />
et enfin je binde le NSTextField de mon interface avec la key timeValue, via un ObjectController de IB.
Et là , tout marche bien !!
Mais je me dis que c'est bête d'avoir créé une variable timeValue quand on fait des bindings surtout que les classes VLCMediaPlayer et VLCTime m'ont l'air d'être KVC-compliantes.
Je teste en faisant provisoirement de mon objet Root un Observer pour la clé time que la mise à jour de cette variable renvoie bien des notifications KVO--> tout est OK.
Puis je basarde ma variable timeValue, l'implémentation de la méthode mediaTimeChanged et je fais de ma variable myPlayer une property :
<br />@property(readonly) VLCMediaPlayer * myPlayer; <br />
Enfin je binde directement mon NSTextField à la key myPlayer.time.stringValue.
Et là patatras, il ya le Null placeHolder dans mon NSTextField au lieu de l'affichage escompté...
Qu'est ce qui ne va pas ?
Si aussi vous voyez des maladresses (par exemple, je suis pas très l'aise sur la necessité de déclarer les variables comme @property pour pouvoir les binder ...), n'hésitez pas !
Merci d'avance pour votre aide.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Ce readonly ne poserait-il pas problème ? Certes ce n'est pas directement myPlayer qui est en binding, mais c'est quand même très lié.
Comment le binding réagit dans ce cas ? Il faudrait essayer sur un exemple simple.Â
Vérifier si les initialisations suivent une bonne chronologie .
Rien n'oblige les @property pour le binding, ceci dit, pour faire le setter et le getter proprement à la main qui agissent correctement ...Â
En fait, je m'interrogeais globalement sur l'utilité des getter/setter (à la main ou à la sauce @property) puisque ça a l'air de très bien marcher sans...
Revenons à nos moutons :
Il ya peut-être effectivement un problème dans les initialisations sachant que myPlayer est créé dans le awakeFromNib. Je l'ai initialisé à ce niveau car il faut une NSView (qui est en IBOutlet) pour l'initialiser et il me semble me souvenir que pour être sûr d'avoir des bons Outlet, il faut attendre d'être dans -awakeFromNib
Après, honte à moi, mais j'avoue que je ne suis pas non plus hyper au taquet entre ce qu'il faut mettre dans le -init et ce qu'il faut mettre dans le -awakeFromNib.
Merci déjà pour cette première réponse !
Mon expérience personnelle, c'est qu'un setter ou un getter qui ne fait que renvoyer la valeur ou donner la valeur est inutile si on utilise valueForKey et setValue:forKey: ou les bindings. Ces méthodes peuvent par contre être utiles pour intercepter une mise à jour ou une demande de valeur en vue d'une action spéciale.
[EDIT] ceci dit la doc est ambigue
Donc, avec les property, on a plus de sécurité sur le bon fonctionnement.
Il y a un moyen simple de le savoir : dans awakeFromNib mettre à jour la valeur bindée sur le modèle
  [[myPlayer time] setValue:@truc forKey:@timeValue]
Si cela se reporte sur le TextField, le binding devrait être au point et il y a de fortes chances que le problème soit dans l'ordre des initialisations.
Oui cela pose problème.
Si tu veux laisser là cette initialisation, il faut faire le binding dans le code et non dans IB.
- (void)bind:(NSString *)binding toObject:(id)observableController withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
Ce que j'ai fait, j'ai initialisé dans mon myPlayer dans le -init et ça marche ...
Doit-on en déduire que l'établissement des bindings se fait entre ces deux méthodes ?
Et même, à quoi sert alors le –awakeFromNib ?
Merci déjà pour ces réponses, je ferai plus attention à ces initialisations la prochaine fois.
Ce qui est certain c'est le message awakeFromNib est envoyé après que le nib ait été désarchivé, et donc que les connections & bindings ait été installés.
Le awakeFromNib sert à des initialisations ultérieures avec le matériel établi justement par ce nib. Par exemple, pour ce qui te concerne, la solution de faire le binding dans le code.
Voir Resource Programming Guide