Binding BOOL ? + Automatically Prepare Contents

AliGatorAliGator Membre, Modérateur
avril 2006 modifié dans Xcode et Developer Tools #1
Bonjour à  tous.

Voilà  je me (re-)mets au bindings et j'ai 2 petits problèmes avec eux + NSArrayController.

Premier problème : comment gérer un binding de type BOOL comme "enabled" ??

Dans mon appli, j'ai un bouton "Save" que je voudrais ne rendre actif que si la variable d'instance "modelLoaded" de mon contrôlleur vaut YES.
1) Je ne peux pas faire une variable d'instance de type BOOL car elle n'est pas KVO.
2) Je me suis donc dit que j'allais passer par un NSNumber... Mais NSMutableNumber n'existant pas, je ne peux pas changer la valeur de ma variable ! (encore moins par KVC)
La seule solution c'est de faire un release suivi d'un alloc/initWithBool, ce qui ne respecte pas le KVC ce qui explique que si je fais ça mon interface n'est pas mise à  jour...  :-\\
3) J'ai aussi essayé de faire un accesseur [tt]-(BOOL)modelLodaded { return (currentFile != nil); }[/tt], mais quand currentFile est modifié (je fais un alloc/init dessusdans ma méthode d'ouverture de fichier) ça ne met pas pour autant l'état de mon bouton à  jour...  :'(
4) J'ai aussi essayé de mettre "currentFile" comme Model Key Path et de choisir "IsNotNil" comme valueTransformer (en fait je n'avais pas vu ces valueTransformers au début d'où mon passage par mon "modelLoaded"), mais ça n'a l'air de rien changer. :why?:

Alors pourquoi mon bouton reste toujours désactivé et qu'il ne reflète pas les changements de ma variable ??
(J'ai vérifié au fait, currentFile est bien != nil même après mon code d'ouverture, j'ai bien fait un retain dessus, il est persistant...)



Deuxième problème : NSArrayController != nil même si "Automatically prepare contents" non coché ?
J'ai aussi un NSArrayController, que je remplis avec un [tt]setContent:[/tt]. (Au passage, j'avais essayé de binder le contentObject de cet ArrayController avec une v.i. de MyController, mais ça a l'air de marcher aussi bien que l'histoire de mon modelLoaded :()
--> Je n'ai pas coché la case "Automatically prepare contents" (puisque je fais un setContent, ça me semblait logique ?)... donc le contenu interne de mon NSArrayController devrait être nil tant qu eje ne fais pas de setContent, non ? (c'est ce que semble dire la doc Cocoa en tout cas)

Le problème c'est que j'ai un bouton "Add" dont l'enabled est bindé au "canAdd" du NSArrayController... et ce bouton est activé au démarrage ! Alors que si mon contenu de ArrayController est nil ça me semblerait logique qu'il ne soit pas être activé, non ?? :)beta:

Autrement dit, comment faire pour que mon bouton Add ne soit actif que lorsque mon NSArrayController aura reçu le setContent (envoyé dans la méthode d'ouverture de fichier) -- ou encore lorsque j'ai "canAdd:" ET "modelLoaded = YES" à  la limite (ce que je sais faire avec un multiple-binding, mais on en revient à  mon premier problème avec modelLoaded)  B)

----


Merci pour vos éclaircissements :)

Réponses

  • 19:30 modifié #2
    Le fait que la variable soit en bool ne change rien au fait qu'elle peut etre observée par KVO. Dans le cas que tu présentes, où la valeur renvoyée est calculée, deux possibilités s'offrent à  toi:
    - soit la valeur renvoyée dépend de 1 (ou plus) variables d'instances, et dans ce cas, il y a la méthode setKeys:triggerNotificationChangesForKey: qui peut fonctionner (dans le cas que tu présentes, elle est dépendante de currentFile donc ça devrait aller.
    - soit la valeur calculée dépend de l'état de variables d'autres objets, que tu observes par KVO et dans ce cas tu peux forcer le système à  envoyer une notification en enchainant un appel de willChangeValueForKey: et didChangeValueForKey:
  • AliGatorAliGator Membre, Modérateur
    avril 2006 modifié #3
    Merci Renaud.

    Bon ben en effet problème résolu : je n'utilisais pas le KVC pour accéder à  ma clé (je n'avais pas fait de setter pour ma variable currentFile et je la modifiait directement au lieu de passer par un setter.

    J'ai donc juste rajouté ce code :
    -(void)setCurrentFile:(NSString*)path<br />{<br />	if (_currentFile == path) return;<br />	[_currentFile release];<br />	_currentFile = [path retain];<br />}
    
    Et je fais [tt][self setCurrentFile:path];[/tt] dans ma méthode d'ouverture de fichier et tout roule :)

    J'ai pas essayé avec la variable modelLoaded et un setter sur ce BOOL mais j'imagine que si je déclare setModelLoaded et que je l'appelle ça marchera tout aussi bien.

    Du coup pour mon bouton "add" j'ai fait un multiple-binding (NSArrayController->canAdd: + MyController->NSIsNotNil(currentFile)) et ça marche.

    Y'a 2 trucs que je capte pas ou plutôt qui ont l'air faux ou pas clairs dans la doc Apple :
    - Il faut absolument créer un "setter" pour notre variable (alors que le KVC dit que s'il n'y en a pas il fait juste une égalité, ce qui n'est pas persistant pour des NSObject* mais l'est pour des BOOL)
    - Même si "Automatically prepare contents" n'est pas coché, le "arrangedObjects" d'un NSArrayController est vide, mais pas nil (ce qui explique que canAdd: est YES et que le bouton "Ajouter" est activé si je fais un single-binding juste sur canAdd, même alors que je n'ai pas encore fait de setContent sur mon arrayController)
  • Eddy58Eddy58 Membre
    19:30 modifié #4

    Dans mon appli, j'ai un bouton "Save" que je voudrais ne rendre actif que si la variable d'instance "modelLoaded" de mon contrôlleur vaut YES.

    Perso, depuis que j'utilise les bindings, je dédie un NSObjectController contenant les clefs nécessaires pour gérer les valeurs et états des variables exploitées par les controles éparses genre boutons, textfields, etc.... Par exemple, dans ce cas, j'aurais mis une key "modelLoaded" dans le NSObjectController, ensuite il n'y aurais plus qu'à  binder le bouton dessus, et modifier la valeur de la clef en conséquence. :) 
  • AliGatorAliGator Membre, Modérateur
    19:30 modifié #5
    dans 1146351967:


    Dans mon appli, j'ai un bouton "Save" que je voudrais ne rendre actif que si la variable d'instance "modelLoaded" de mon contrôlleur vaut YES.

    Perso, depuis que j'utilise les bindings, je dédie un NSObjectController contenant les clefs nécessaires pour gérer les valeurs et états des variables exploitées par les controles éparses genre boutons, textfields, etc.... Par exemple, dans ce cas, j'aurais mis une key "modelLoaded" dans le NSObjectController, ensuite il n'y aurais plus qu'à  binder le bouton dessus, et modifier la valeur de la clef en conséquence. :)   
    Oui et non car en fait le problème est que sans faire gaffe, je ne respectais pas le KVC/KVO : je faisais : [tt]maVariable = nouvelleValeur[/tt] au lieu de faire [tt][self setValue:nouvelleValeur forKey:maVariable[/tt] ou encore [tt][self setMaVariable:nouvelleValeur][/tt]

    Donc j'aurais dédié un ObjectController spécialement pour mes bindings que ça n'aurait rien changé :-/

    Là  où j'avais mal décodé la doc c'est que dans la doc du KVC Apple dit que s'il n'y a pas d'accesseur dédié, il va essayer de trouver une variable d'instance ayant le nom spécifié et modifier sa valeur directement (et s'il ne trouve pas, il essaye avec un "_" devant le nom). Mais -- et c'était là  l'erreur -- dans ce cas, la variable ne passe par par la procédure de KVO habituelle, c'est à  dire que dans ce cas (changement direct de la variable d'instance sans passer par un explicite [tt]setValue: forKey:[/tt] ou [tt]setVariable:[/tt]), la notification de changement de valeur n'est pas envoyée, donc le binding n'est pas mis à  jour !
  • Eddy58Eddy58 Membre
    19:30 modifié #6
    dans 1146408243:

    Donc j'aurais dédié un ObjectController spécialement pour mes bindings que ça n'aurait rien changé :-/

    Si. En plus de lui confier les valeurs et états de controles éparses, tu lui laisses les clefs gérées par tes méthodes accesseurs (qui n'ont alors plus lieu d'être), et ça fait encore une chose de moins à  s'occuper. Plutot que de sous-classer NSObject pour faire un contrôleur, maintenant j'ai plus tendance à  sous-classer NSObjectController, ce qui facilite quand même bien les choses. :)
  • AliGatorAliGator Membre, Modérateur
    19:30 modifié #7
    Ahhhh oui pardon
    Je ne pensais pas au "vrai" ObjectController, mais à  un contrôlleur d'objet (sous-classe de NSObject), en effet j'avais mal lu :)
Connectez-vous ou Inscrivez-vous pour répondre.