awakeFromNib exécutée deux fois

RocouRocou Membre
02:45 modifié dans API AppKit #1
Ma méthode awakeFromNib et exécutée deux fois et je ne vois pas comment empêcher cela.

dans la doc il est dit ceci:

It is recommended that you maintain a one-to-one correspondence between your File's Owner objects and their associated nib files. Loading two nib files with the same File's Owner object causes that object's awakeFromNib method being called twice, which could cause some data structures to be reinitialized in undesired ways. It is also recommended that you avoid loading other nib files from your awakeFromNib method implementation.

Mais ce paragraphe est du charabia pour moi.

Réponses

  • mpergandmpergand Membre
    02:45 modifié #2
    -(void) awakeFromNib<br />{<br />	static BOOL init=FALSE;<br />	if(init) return; init=TRUE;<br />	<br /><br />&nbsp; // ton code ici<br />}
    
  • CéroceCéroce Membre, Modérateur
    02:45 modifié #3
    Tous les objets que tu vois dans le NIB, y compris le File's Owner, reçoivent le message -awakeFromNib.

    Ils te disent que si tu charges un NIB, par exemple avec un NSWindowController (=File's Owner), et que tu le charges ensuite un autre NIB avec ce même window controller, -awakeFromNib va être appelée deux fois. Comme on se sert de cette méthode pour initialiser les objets connectés, il y a effectivement du grabuge en perspective.


    Mais ce n'est pas ton problème. Déjà , c'est quoi ton objet dont la méthode -awakeFromNib est appelé deux fois ? N'as-tu tout simplement pas deux exemplaires de cet objet dans deux NIB différents, ou le même NIB ?
  • RocouRocou Membre
    02:45 modifié #4
    dans 1244739688:

    Mais ce n'est pas ton problème. Déjà , c'est quoi ton objet dont la méthode -awakeFromNib est appelé deux fois ? N'as-tu tout simplement pas deux exemplaires de cet objet dans deux NIB différents, ou le même NIB ?

    J'avais bien deux NIB (english et french). J'ai supprimé english mais ça ne change rien.
    Comment peut-on voir si l'objet est deux fois dans le même NIB?

    Il s'agit d'une classe "de type" NSView. J'ai donc un fichier.m et un fichier.h ainsi qu'un petit cube bleu du nom de ma classe dans le MainMenu.xib. Peut-être est-ce ici que ça coince?

    PS: mpergand, merci ton code fonctionne parfaitement mais j'aimerais quand même comprendre  :) )
  • CéroceCéroce Membre, Modérateur
    juin 2009 modifié #5
    Tu as deux instances de ta NSView:
    - la première dans la fenêtre
    - la seconde, le cube bleu. => À virer.

    C'est pour ça que la méthode est appelée deux fois.
    Tu peux t'arrêter avec le débogueur dans -awakeFromNib, et tu constateras que self a des valeurs différentes (=> deux instances différentes) lors des deux appels.

  • mpergandmpergand Membre
    02:45 modifié #6
    dans 1244740409:

    Il s'agit d'une classe "de type" NSView. J'ai donc un fichier.m et un fichier.h ainsi qu'un petit cube bleu du nom de ma classe dans le MainMenu.xib. Peut-être est-ce ici que ça coince?



    Newbie error spotted  ;)

    grillé par céroce

  • RocouRocou Membre
    02:45 modifié #7
    dans 1244740950:

    Tu as deux instances de ta NSView:
    - la première dans la fenêtre
    - la seconde, le cube bleu. => À virer.

    C'est pour ça que la méthode est appelée deux fois.
    Tu peux t'arrêter avec le débogueur dans -awakeFromNib, et tu constateras que self a des valeurs différentes (=> deux instances différentes) lors des deux appels.

    Merci. Je me doutais bien que le problème venait de là . Mais si je vire le cube bleu, comment réaliser mes liaisons sous IB?
    (J'ai notamment une liaison entre un NSScrollView et le cube afin de gérer le scroll de ma vue)
  • RocouRocou Membre
    02:45 modifié #8
    dans 1244741642:

    Newbie error spotted  ;)

    :)
    N'est-on pas dans le fil "Grands débutants"?
  • mpergandmpergand Membre
    02:45 modifié #9
    Model View Controller

    Le cube bleu est le controller et NSScrollView la vue.
  • RocouRocou Membre
    juin 2009 modifié #10
    dans 1244789921:

    Le cube bleu est le controller et NSScrollView la vue.

    Je n'arrive pas à  faire le lien entre mon contrôleur et la vue. Par exemple,
    J'ai déclaré un outlet dans mon contrôleur  IBOutlet NSView *maVue;
    Je réalise la liaison sous IB entre la NSView et mon controleur et à  la compilation j'obtiens une erreur: error 'maVue' undeclared (first use in this function)
  • CéroceCéroce Membre, Modérateur
    02:45 modifié #11
    Sans voir le code, difficile de te répondre. Mais sache que si la liaison est mal faà®te dans IB, l'outlet vaudra nil, mais qu'aucune erreur ne te sera signalée.
  • RocouRocou Membre
    02:45 modifié #12
    dans 1244792216:

    Sans voir le code, difficile de te répondre. Mais sache que si la liaison est mal faà®te dans IB, l'outlet vaudra nil, mais qu'aucune erreur ne te sera signalée.

    J'ai dû mal m'exprimer.
    Je désire dessiner dans une vue, je dois donc implémenter les méthodes "initWithFrame" et "drawRect".


    J'avais donc créé une classe "maVue" de type NSView dans laquelle j'avais implémenté initWithFrame et drawRect. Et à  partir de là , je suis perdu.
    Les méthodes mouseDown, mouseUp, etc., je dois les mettre où? Dans mon contrôleur ou dans ma classe "maVue"? Comment partager toutes les variables dont j'ai besoin dans mon contrôleur ET dans "maVue"?
    C'est pour cela que j'avais tendance à  mettre tout mon code dans la classe "maVue" et ne presque pas utiliser mon contrôleur.
  • CéroceCéroce Membre, Modérateur
    02:45 modifié #13
    Les méthodes mouseDown: et compagnie appartiennent à  NSResponder dont hérite NSView.

    Pour reformuler ta question: "Comment échanger les données entre la vue et le modèle", il y a plusieurs réponses possibles; savoir quelle solution adopter fait partie du talent du développeur.
    Comme je pense que tu es toujours sur ta vue qui affiche le planning, tu pourrais t'inspirer du modèle de la Data Source utilisé un peu partout dans Cocoa (notamment les table views, p. 102 du livre d'Hillegass).
  • AliGatorAliGator Membre, Modérateur
    02:45 modifié #14
    Heu j'ai l'impression qu'il y a un peu mélange dans ta tête entre classe et instance de classe :
    dans 1244791596:
    Par exemple, J'ai déclaré un outlet dans mon contrôleur  IBOutlet NSView *maVue;
    dans 1244801250:
    Je désire dessiner dans une vue, je dois donc implémenter les méthodes "initWithFrame" et "drawRect".
    J'avais donc créé une classe "maVue" de type NSView dans laquelle j'avais implémenté initWithFrame et drawRect.


    En effet il faut créer une classe MaVue (note je met une majuscule au nom de la classe "MaVue", c'est une conventionne de nomage que tout le monde utilise, pour les différencier des instances que l'on nomme en général avec la première lettre en munuscule), classe qui sera une sous-classe de (qui dérivera de la classe) NSView, et dans laquelle tu vas réimplémenter drawRect et initWithFrame. C'est donc un nouveau type d'objet, certes une NSView, mais qui sera spécialisée à  ton besoin.

    Et ensuite dans ton NIB, au lieu de mettre une NSView dans ton interface, tu vas alors placer un objet MaVue (bon dans les faits tu vas placer une NSView parce que tu n'as que ça dans ta bibliothèque dans IB, et tu vas ensuite changer sa classe dans l'inspecteur pour dire qu'en fait c'est pas une NSView générique mais plus particulièrement une MaVue). Tu vas ainsi créer une instance de la classe MaVue dans ton interface graphique.

    Ensuite dans ton contrôlleur, si tu as besoin d'accéder à  ta vue, tu vas créer un IBOutlet, dont le type est le type de ton objet, et le nom est un nom de variable arbitaire... comme tout IBOutlet. Donc tu vas écrire par exemple [tt]IBOutlet MaVue* maVuePrincipale;[/tt] ce qui va te permettre de relier ton objet de type MaVue que tu as placé dans ton interface à  cet IBOulet.

    Pour bien te faire comprendre, si tu veux créer une 2e vue qui se comporte pareil que ta première, tu peux placer un autre objet MaVue dans ton interface, et avoir dans ton contrôleur pour y accéder un autre "IBOutlet MaVue* maVueSecondaire" (tout comme tu peux placer plusieurs NSButtons ou NSTextFields dans une fenêtre et avoir des IBOutlets vers ces boutons ou textFields). Ce sera alors une autre instance de la même classe MaVue. Qui appellera comme toutes les instances de la classe NSView (et de la classe MaVue qui en dérive) la méthode "drawRect" de sa classe au moment où elle a besoin d'être dessinée. Et comme il se trouve que c'est un objet de type MaVue, c'est le code implémenté dans MaVue qui sera exécuté, puisqu'il va "remplacer" celui plus générique de NSView pour les instances de classe MaVue.
  • RocouRocou Membre
    02:45 modifié #15
    dans 1244805290:

    En effet il faut créer une classe MaVue (note je met une majuscule au nom de la classe "MaVue", c'est une conventionne de nomage que tout le monde utilise, pour les différencier des instances que l'on nomme en général avec la première lettre en munuscule), classe qui sera une sous-classe de (qui dérivera de la classe) NSView, et dans laquelle tu vas réimplémenter drawRect et initWithFrame. C'est donc un nouveau type d'objet, certes une NSView, mais qui sera spécialisée à  ton besoin.

    Et ensuite dans ton NIB, au lieu de mettre une NSView dans ton interface, tu vas alors placer un objet MaVue (bon dans les faits tu vas placer une NSView parce que tu n'as que ça dans ta bibliothèque dans IB, et tu vas ensuite changer sa classe dans l'inspecteur pour dire qu'en fait c'est pas une NSView générique mais plus particulièrement une MaVue). Tu vas ainsi créer une instance de la classe MaVue dans ton interface graphique.

    Ensuite dans ton contrôlleur, si tu as besoin d'accéder à  ta vue, tu vas créer un IBOutlet, dont le type est le type de ton objet, et le nom est un nom de variable arbitaire... comme tout IBOutlet. Donc tu vas écrire par exemple [tt]IBOutlet MaVue* maVuePrincipale;[/tt] ce qui va te permettre de relier ton objet de type MaVue que tu as placé dans ton interface à  cet IBOulet.

    Pour bien te faire comprendre, si tu veux créer une 2e vue qui se comporte pareil que ta première, tu peux placer un autre objet MaVue dans ton interface, et avoir dans ton contrôleur pour y accéder un autre "IBOutlet MaVue* maVueSecondaire" (tout comme tu peux placer plusieurs NSButtons ou NSTextFields dans une fenêtre et avoir des IBOutlets vers ces boutons ou textFields). Ce sera alors une autre instance de la même classe MaVue. Qui appellera comme toutes les instances de la classe NSView (et de la classe MaVue qui en dérive) la méthode "drawRect" de sa classe au moment où elle a besoin d'être dessinée. Et comme il se trouve que c'est un objet de type MaVue, c'est le code implémenté dans MaVue qui sera exécuté, puisqu'il va "remplacer" celui plus générique de NSView pour les instances de classe MaVue.

    Tout ceci, j'avais bien compris et ça fonctionne très bien. Ton intervention à  le grand mérite de confirmer cela et surtout c'est formulé de façon très claire. Je t'en remercie.

    Mais en tant que débutant j'ai du mal à  m'exprimer de façon correcte.
    Si je veux récupérer les données d'une NSScrollView dans le code de MaVue, comment faire?
    J'ai créé un outlet de type NSScrollView dans MaVue mais comment réaliser le lien avec mon NSScrollView?
    Avec un cube bleu, c'était facile mais sans ce cube, je ne sais pas comment faire.
  • CéroceCéroce Membre, Modérateur
    02:45 modifié #16
    dans 1244813561:

    Si je veux récupérer les données d'une NSScrollView dans le code de MaVue, comment faire?

    Cette question est étrange, une NSScrollView ne contient pas vraiment de données, elle contient d'autres vues  ???

    dans 1244813561:

    J'ai créé un outlet de type NSScrollView dans MaVue mais comment réaliser le lien avec mon NSScrollView?

    On ajoutant une outlet à  ta vue et en la reliant à  la NSScrollView.

    Si la scrollview contient ta vue, tu peux aussi appeler [superview] qui va te renvoyer la NSClipView qui contient ta vue, puis encore [superview] pour obtenir la scrollview.

    J'ai l'impression que tu fais quelque chose d'étrange, dis-nous plutôt quel est le résultat recherché.

  • RocouRocou Membre
    02:45 modifié #17
    dans 1244815451:

    On ajoutant une outlet à  ta vue et en la reliant à  la NSScrollView.

    Oui mais comment physiquement réaliser ce lien?
    Sous IB les instances MaVue et NSScrollView sont "confondues", comment tirer un lien de l'une à  l'autre?

    dans 1244815451:

    J'ai l'impression que tu fais quelque chose d'étrange, dis-nous plutôt quel est le résultat recherché.


    Et bien dans MaVue, j'ai le code suivant:

    -(void)recupDonneesScroll:(NSNotification *)aNotification<br />{<br />	// get the changed content view from the notification<br />&nbsp; &nbsp; NSView *changedContentView=[aNotification object];<br />	<br />&nbsp; &nbsp; // get the origin of the NSClipView of the scroll view that<br />&nbsp; &nbsp; // we&#39;re watching<br />&nbsp; &nbsp; NSPoint changedBoundsOrigin = [changedContentView bounds].origin;<br />	<br />&nbsp; &nbsp; // get our current origin<br />&nbsp; &nbsp; NSPoint curOffset = [[leScroll contentView] bounds].origin;<br />&nbsp; &nbsp; NSPoint newOffset = curOffset;<br />	<br />&nbsp; &nbsp; // scrolling is synchronized in the vertical plane<br />&nbsp; &nbsp; // so only modify the y component of the offset<br />&nbsp; &nbsp; newOffset.y = changedBoundsOrigin.y;<br />	newOffset.x = changedBoundsOrigin.x;<br />	<br />	[self setOrigineLocationY:&nbsp; newOffset.y];<br />	[self setOrigineLocationX:&nbsp; newOffset.x];<br />	<br />&nbsp; &nbsp; [self setNeedsDisplay:YES]; <br />}<br />
    


    Le machin qui s'appelle 'leScroll' (vers le milieu de ce bout de code) doit être de type NSScrollView.
    Le but est de faire en sorte que ma ligne et ma colonne d'entêtes restent au même endroit quand l'utilisateur se sert des ascenseurs. La notification sert donc à  récupérer les coordonnées du NSClipView au sein de la NSScrollerView (si j'ai bien compris  :) )

    A l'origine j'avais déclaré un IBOutlet NSScrollView *leScroll; dans MaVue. Puis j'avais relié mon cube bleu (la seconde instance de MaVue) au NSScrollView. ça fonctionnait très bien.


  • CéroceCéroce Membre, Modérateur
    02:45 modifié #18
    Tu peux obtenir la scrollview ainsi:

    NSScrollView* scrollView = [[self superview] superview];
    


    Mais c'est un peu crade, parce que ça implique que ta vue est dans une scrollview (elle n'est donc plus réutilisable dans une autre situation).

    Si ça marchait avec le cube bleu, c'est parce que toutes les instances de MaVue reçoivent la notification. L'instance du cube bleu n'était pas affichée, mais elle réagissait quand même à  la notification et la communiquait à  la scrollview.


    Voici une autre méthode, plus propre: créer un objet intermédiaire (héritier de NSObject) qui reçoit la notification et possède deux outlets: une vers la scrollview et une vers la MaVue.
  • zoczoc Membre
    02:45 modifié #19
    dans 1244817536:

    dans 1244815451:

    On ajoutant une outlet à  ta vue et en la reliant à  la NSScrollView.

    Oui mais comment physiquement réaliser ce lien?
    Sous IB les instances MaVue et NSScrollView sont "confondues", comment tirer un lien de l'une à  l'autre?


    En changeant le mode d'affichage de la fenêtre principale d'IB afin qu'elle affiche la hiérarchie des instances crées au lieu d'afficher uniquement les objets racine.
  • RocouRocou Membre
    02:45 modifié #20
    dans 1244819230:

    Voici une autre méthode, plus propre: créer un objet intermédiaire (héritier de NSObject) qui reçoit la notification et possède deux outlets: une vers la scrollview et une vers la MaVue.

    Oui, c'est ce que j'ai fait; un objet intermédiaire mais de type NSScrollView, comme ça je récupère directement mes données. Hop!

    Merci à  tous.
  • RocouRocou Membre
    02:45 modifié #21
    dans 1244876216:

    En changeant le mode d'affichage de la fenêtre principale d'IB afin qu'elle affiche la hiérarchie des instances crées au lieu d'afficher uniquement les objets racine.

    Ha oui, ça serait génial si je savais faire cela  :)
  • schlumschlum Membre
    02:45 modifié #22
    Quand tu glisses ton lien vers ta vue, tu peux sélectionner soit la scrollView, soit ce qu'il y a à  l'intérieur...  ???
  • schlumschlum Membre
    02:45 modifié #23
    Et pour afficher par hiérarchie, c'est tout simple :

  • zoczoc Membre
    02:45 modifié #24
    dans 1245064194:

    Et pour afficher par hiérarchie, c'est tout simple :


    Merci pour les copies d'écran  :P

    (Ca me paraissait tellement évident que j'ai eu la flemme de les faire moi même  :) )
  • RocouRocou Membre
    02:45 modifié #25
    dans 1245064070:

    Quand tu glisses ton lien vers ta vue, tu peux sélectionner soit la scrollView, soit ce qu'il y a à  l'intérieur...  ???

    Ha bon? Chez moi ça ne fonctionne pas comme ça. Je glisse mon lien mais c'est toujours la même chose qui est sélectionné (en l'occurrence la NSView 'MaVue')
  • RocouRocou Membre
    02:45 modifié #26
    dans 1245064194:

    Et pour afficher par hiérarchie, c'est tout simple :

    Ha super! Je n'avais jamais testé le glissé de lien entre les différents éléments de cette fenêtre  :)

    Merci à  tous.
Connectez-vous ou Inscrivez-vous pour répondre.