Pointeurs, string et binding : question de conception

colas_colas_ Membre
avril 2013 modifié dans Objective-C, Swift, C, C++ #1
Bonjour,

voilà  mon problème :



J'ai deux classes : une classe A et une classe B.
  • La classe A a un attribut NSString, disons myText.
  • La classe B est chargée de présenter ce texte dans une fenêtre pour l'éditer.

    La classe B est appelée par la classe A.


Comment faire en sorte que les mises à  jour du texte faites dans la fenêtre (via classe B ) soit prises en compte par classe A ?



J'ai pensé à  deux solutions qui ne fonctionnent pas :
  1. Ajouter un attribut myTextForB dans classe B.

    Créer une méthode d'initialisation initClassBwithString.

    Quand la classe A crée classe B, lui passer myText en argument.

    Dans la classe B, faire un binding (via IB) entre myTextForB et le NSTextView



    ça ne marche pas, car quand classe B modifie la valeur des chaà®nes de caractère, elle change l'adresse. En gros, myText dans classe A pointe toujours sur la même string.
  2. Du coup, je me suis dit :

    Faire le binding dans le code, directement.

    Passer l'objet A comme argument lors de l'initialisation à  B.

    Dans une méthode de type awakeFromNib créer un binding, du genre :
    <br />
    							[myTextView bind:@&quot;value&quot; toObject:objetA withKeyPath:@&quot;myText&quot; options:nil] ;	<br />


    Je ne sais pas pourquoi, mais ça ne marche pas.


Avez-vous des idées ?

Je n'ai pas encore testé mais j'ai pensé à  un NSMutableString.

Je voulais avoir vos idées là -dessus car il me semble que c'est assez classique.



Merci !

Réponses

  • LeChatNoirLeChatNoir Membre, Modérateur
    De ce que tu décris, je dirai que :

    => A est ta classe modèle

    => B est ta classe contrôleur (car tu conceptualise en MVC bien sur).



    Donc B doit instancier A, ou avoir un pointeur vers A, et va "binder" ce pointeur avec le textfield qui le présente.



    nan ?
  • En fait, A est plus une classe-controlleur mère et B une classe-controlleur fille.

    Dans mon cas, A est une NSDocument et B une NSWindowController
  • laudemalaudema Membre
    avril 2013 modifié #4
    'colas2' a écrit:


    En fait, A est plus une classe-controlleur mère et B une classe-controlleur fille.

    Dans mon cas, A est une NSDocument et B une NSWindowController


    Pour le 2) Si A est une propriété de B alors tu peux lier bTextView.value à  self.A.myText.

    Pour le 1) Ecrire le setter de myTextForB et dedans faire la modification de myTextInA.

    Pour les 2 : mettre des points d'arrêt et regarder les valeurs des objets : un objet nil ne lance pas d'erreur quand on lui envoie un message, le message est simplement ignoré ..

    NB : On peut mettre un point d'arrêt sur @synthesize pour regarder la valeur d'une propriété quand elle est accédée ..
  • The future will often come Kazakhstan, chatting together, good fun ah, I like the atmosphere here.

    Buy Diablo 3 Gold

    Cheap Diablo 3 Gold

    Buy Guild Wars 2 Gold
  • 'wangli00110' a écrit:


    The future will often come Kazakhstan, chatting together, good fun ah, I like the atmosphere here.




    WTF ? image/sad.png' class='bbc_emoticon' alt=':(' />
  • colas_colas_ Membre
    avril 2013 modifié #7
    Tu as vu juste je pense !!



    Oui, j'envoyais des messages à  nil.

    En fait, j'essaye d'accéder au document en cours à  l'aide de la commande
    <br />
    [[NSDocumentController sharedDocumentController] currentDocument]<br />




    Mais, il semble que cette commande ne marche pas quand je l'appelle depuis un NSWindowController. Comme si le fait que ce soit une nouvelle fenêtre lui fasse perdre le chemin du document en question.



    Du coup, je me demande si ce serait pertinent de lui passer le document en cours en argument.



    Sinon,

    << [font=helvetica, arial, sans-serif]Pour le 1) Ecrire le setter de myTextForB et dedans faire la modification de myTextInA. >>[/font]

    c'est très joli !



    Merci !





    PS :

    Pour le binding dans le code, ce qui suit te semble-t-il OK ?
    <br />
    [myTextView bind:@&quot;value&quot; toObject:objetA withKeyPath:@&quot;myText&quot; options:nil] ;<br />
  • mpergandmpergand Membre
    avril 2013 modifié #8
    <br />
      NSDictionary* dic=[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:NSContinuouslyUpdatesValueBindingOption];<br />
        [oTextView bind:@&quot;value&quot; toObject:self withKeyPath:@&quot;stringResult&quot; options:dic];<br />




    Il faut décocher l'option "Rich Text" dans IB.



    Les bindings c'est le bazar ...
  • colas_colas_ Membre
    avril 2013 modifié #9
    Tiens, je te pose une question : si je ne choisis pas "Continuous update", à  quel moment se fait l'update ?



    merci !



    PS : j'avais bien décocher RTF, mais c'est peut-être ce "continuous update" qui me manquait...
  • 'laudema' a écrit:


    Pour le 1) Ecrire le setter de myTextForB et dedans faire la modification de myTextInA.




    ça marche, en passant mon NSDocument en argument à  mon NSWindowController
  • 'mpergand' a écrit:

    <br />
      NSDictionary* dic=[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:NSContinuouslyUpdatesValueBindingOption];<br />
    	[oTextView bind:@&quot;value&quot; toObject:self withKeyPath:@&quot;stringResult&quot; options:dic];<br />




    Il faut décocher l'option "Rich Text" dans IB.



    Les bindings c'est le bazar ...




    Rien n'y fait, ça ne marche toujours pas avec les bindings "dans le code".

    Merci quand même !!



    (L'autre solution marche)
  • mpergandmpergand Membre
    avril 2013 modifié #12
    Bon, on va essayer d'éclaircir les choses ...



    Tu veux faire un lien entre un textView dans une fenêtre secondaire avec une variable d'instance de ton document.



    La méthode qui implémente ce lien doit connaà®tre à  la fois le textView et la variable d'instance.

    Est-ce que le document doit connaà®tre un objet d'interface qui se trouve dans une fenêtre secondaire, à  priori non, c'est au windowController de cette fenêtre.



    Si on considère que NSDocument est le controller maà®tre, alors c'est à  lui de donner les ordres: toi windowController, établis-moi un lien entre ton textView et ma variable.



    Donc concrètement, j'ajouterais au WindowController une méthode du genre:
    <br />
    -(void) bindTextViewWithObject:(id) obj withKeyPath:(NSString *)keyPath<br />




    Sinon, je ne suis pas persuadé que dans ce cas précis les bindings soient vraiment indispensable, à  moins que tu veilles une mise à  jour en continu de la variable de ton document.
  • 'colas2' a écrit:


    Tiens, je te pose une question : si je ne choisis pas "Continuous update", à  quel moment se fait l'update ?


    La réponse est dans la documentation image/wink.png' class='bbc_emoticon' alt=';)' />

    Quand l'objet en cours d'édition arrête de l'être, autrement dit quand l'utilisateur quitte le champ (ou la vue) via la touche tabulation | enter | retour-chariot | click dans une autre vue...
  • Il semble (dans le cas d'une fenêtre auxiliaire) que quand je ferme la fenêtre, le update n'est pas fait.


  • colas_colas_ Membre
    avril 2013 modifié #15



    Rien n'y fait, ça ne marche toujours pas avec les bindings "dans le code".

    Merci quand même !!


    (L'autre solution marche)


     


    J'ai une hypothèse là -dessus : 


    dans mon code, j'initialise ma fenêtre auxiliaire et dans la foulée je crée mon binding.


    Mais alors je vais trop vite car la NSTextView n'a pas eu le temps de se réveiller du NIB.


     


    J'ai déjà  été confronté à  ce genre de problème.


    Par exemple, je dois faire un [myTextField setStringValue:@Coucoujuste après une init.


    La méthode que j'ai trouvée, mais que je ne trouve pas super élégante (à  mon avis il doit y avoir des défauts de conception dans mes classes) c'est un truc du genre :


    • je crée un variable d'instance myVarText
    • je crée une méthode setMyText:(NSString *)aString
    • dans cette méthode, je fais [myTextField setStringValue:@Coucou mais en plus, je remplis myVarText  avec la string  passée en argument
    • enfin j'ajoute une commande dans awakeFromNIB (ou similaire) ou je réappelle setMyText

     


     


     


    Quand je dis qu'il y a un problème de conception, c'est peut-être parce que tous mes NIB devrait être appelés au début ?


    Mes fenêtres auxiliaires (genre préférences) devraient être réveillées dès le début ?


     


    D'un autre côté, les réveiller alors que personne ne va les appeler, c'est peut-être utiliser de la mémoire pour rien.


     


     


    Au final, il y avait deux problèmes :


    • la fenêtre auxiliaire ne connaà®t pas son document (ce qui flaire aussi le problème de conception)
    • le réveil du NIB

     


    Merci de votre aide :)


     


     


    PS : ce qui serait bien, ce serait d'avoir dans Cocoa, des méthode du genre :



    [myWindowController doWhenWindowIsLoaded:(id) obj withMessage:(SEL)message]

     


    et de même pour les NSView


     


     


     


     


    (Remarque : 


    J'ai @property ;(unsafe_unretained) IBOutlet NSTextView *preambuleTextView;


    sans @synthesize


     


    mais xCode ne me gueulait pas dessus quand j'utilisais la variable preambuleTextView, au lieu de _preambuleTextView...


     


    ce qui m'a fait perdre 10minutes :)


     


    Est-ce normal qu'il ne m'ait pas engueulé ?


    )


  • la fenêtre auxiliaire ne connaà®t pas son document (ce qui flaire aussi le problème de conception)


     


    Ajoute le windowController au document et regarde si ça change quelque chose.


     


    - (void)addWindowController:(NSWindowController *)aController (NSDocument)


  • colas_colas_ Membre
    avril 2013 modifié #17

     x


  • colas_colas_ Membre
    avril 2013 modifié #18

    Ajoute le windowController au document et regarde si ça change quelque chose.


     


    - (void)addWindowController:(NSWindowController *)aController (NSDocument)


     


    Mystère : le document est maintenant reconnu direct sans ta méthode !


    Je ne sais pas ce qui s'est passé !


     


    En somme, un long détour pour rien :)


     


    Mais merci quand même !


  • colas_colas_ Membre
    avril 2013 modifié #19

    Remarque : 


    J'ai @property ;(unsafe_unretained) IBOutlet NSTextView *preambuleTextView;


    sans @synthesize


     


    mais xCode ne me gueulait pas dessus quand j'utilisais la variable preambuleTextView, au lieu de _preambuleTextView...


     


    ce qui m'a fait perdre 10minutes :)


     


    Est-ce normal qu'il ne m'ait pas engueulé ?


     


     


    J'ai la réponse et cela pourra vous interpeler je pense :)


    Voilà  mon préambule :



    @interface WindowControllerForPreambule : NSWindowController
    {
    NSTextView * preambuleTextView ;
    }
    @property (unsafe_unretained) IBOutlet NSTextView *preambuleTextView;

     


    mais je n'ai pas de


     



    @synthesize

     


     


     


    Et le bilan de tout ça : c'est que preambuleTextView est nil !!!


    Mais pas _preambuleTextView !!


     


     


    à‰trange !


    Mais je suis sûr que ceux qui comprennent bien tout ceci ont une explication.


     


    Merci !


  • Si tu n'as pas de @synthesize, par défaut la propriété preambuleTextView est attachée à  la variable d'instance _preambuleTextView.


    Le compilateur ne t'empêche pas de définir une autre variable d'instance preambuleTextView.


    Mais c'est périlleux car la confusion est facile. La preuve ...


  • Bien vu !


  • mpergandmpergand Membre
    avril 2013 modifié #22

    Mystère : le document est maintenant reconnu direct sans ta méthode !


    Je ne sais pas ce qui s'est passé !


     


    Tout est normal, l'informatique ce n'est pas de la magie ...


     


    Lorsque que tu fais:


    [[NSDocumentController sharedDocumentController] currentDocument]


     


    à  partir du windowController secondaire, cette méthode recherche qu'elle est la fenêtre active (main window) et recherche à  quel document appartient cette fenêtre. Comme cette fenêtre secondaire n'appartient à  aucun document, cette méthode retourne nil.


     


    Mais si tu ajoutes ce windowController au document, le problème disparaà®t, logiquement !


     


     


    Maintenant, cette fenêtre secondaire est à  priori une mauvaise idée (bad design), il serait plus pertinent de l'afficher comme une  sheet ou alors comme une palette (NSPanel).


     


    Un NSPanel actif n'est pas main window, donc tu peux savoir à  partir de ce panel qu'elle est le document actif, via la méthode sus-cité.


  • Mais si tu ajoutes ce windowController au document, le problème disparaà®t, logiquement !


     


    Oui, mais je ne l'ai pas ajoutée !

  • Whoua ! c'est magique alors  :p


  • DrakenDraken Membre
    avril 2013 modifié #25
    C'est quoi la marque de ta poupée vaudou ?
Connectez-vous ou Inscrivez-vous pour répondre.