Pb avec NSWindowController et Appli multi XIB

FloFlo Membre
14:23 modifié dans API AppKit #1
Bonjour,

Je suis actuellement sur une appli coreData (non Document-based) et je souhaite charger plusieurs fichiers XIB à  l'aide de NSWindowController.

Dans un premier fichier XIB (MainMenu.xib) je créer un controller délégué de NSApplication (également propriétaire du xib) et qui gère donc la fonction :

<br />- (void) applicationDidFinishLaunching: (NSNotification*)notification<br />{<br />&nbsp;  ...<br />	mainWindowController = [[ITMainWindowController alloc] initWithWindowNibName: @&quot;MainWindow&quot;];<br />	[mainWindowController showWindow: nil];<br />&nbsp;  ...<br />}<br />


ITMainWindowController(propriétaire de MainWindow.xib) comporte une fonction :

<br />- (void) awakeFromNib<br />{<br />	[[self window] setAutorecalculatesContentBorderThickness: YES forEdge: NSMinYEdge];<br />	[[self window] setContentBorderThickness: 30 forEdge: NSMinYEdge];<br />}<br />


Or lorsque je lance l'application, la window (connectée à  l'ITWindowController) ne s'affiche pas et le programme se fige sans ne rien afficher dans le log.

J'ai essayé de mettre la méthode awakeFromNib: en commentaire et de faire un NSlog() :

<br />- (void) applicationDidFinishLaunching: (NSNotification*)notification<br />{<br />&nbsp;  ...<br />	mainWindowController = [[ITMainWindowController alloc] initWithWindowNibName: @&quot;MainWindow&quot;];<br />	[mainWindowController showWindow: nil];<br /><br />&nbsp; &nbsp; NSLog(@&quot;%@&quot;, [mainWindowController window]);<br />&nbsp;  ...<br />}<br />


Le log affiche : (nil) et la fenêtre s'affiche  :-\\

Pourtant la NSWindow de MainWindow.xib est bien connectée au ITMainWindowController également file's owner du xib. La question est, comment le ITMainWindowController à  pu éxécuter la méthode showWindow: correctement alors que lorsqu'on lui fait window: (dans son awakeFromNib: ou après showWindow:) il renvoit nil ?  :crackboom:-

Un peu d'aide serait la bienvenue, je sais que ce que je suis en train de faire peut marcher puisque je l'ai vu dans un exemple fourni par Apple (SourceView pour ceux qui connaissent, que je conseil au débutant pour le nombre de chose qu'on peut apprendre ;)).

Merci d'avance pour vos réponses...

Flo




Réponses

  • NoNo Membre
    14:23 modifié #2
    La méthode awakeFromNib ne peut pas être appelée, car l'objet ITMainWindowController est créé par programme (alloc/init), et non pas par un .nib.
  • FloFlo Membre
    juillet 2008 modifié #3
    Le fait qu'ITMainWindowController soit le file's owner du nib ne devrait-il pas rendre possible l'appel de la méthode awakeFromNib: ?

    Dailleur, awakeFromNib est bien exécutée puisque c'est le code qui est dedans qui fait planter l'appli, en l'occurence
    [self window];

    L'exemple que j'ai trouvé le fait parfaitement pourtant...

    Pour ceux qui ont le courage d'aller voir (prenez le temps de l'étudier, ya plein de choses intéressantes dedans, pour les débutants du moins  ;) ) :
    http://developer.apple.com/samplecode/SourceView/index.html

    Leur NSWindowController s'appelle MyWindowController et est créé par programmation dans une méthode de l'appDelegate et pourtant sa méthode awakeFromNib est bien appelée et est surtout capable de modifier la NSWindow associée. Je ne comprend pas pourquoi chez moi sa ne marche pas, aurais-je raté une subtilité ?
  • Philippe49Philippe49 Membre
    14:23 modifié #4
    Ce ne serait pas que ton fichier nib n'est pas déclaré dans les ressources de ton projet XCode ?

    En général, je fais
    1) Add > New File sur le resources group de XCode
    2) j'ouvre le fichier .nib ainsi créé
    3) j'affecte la classe au File's owner


  • NoNo Membre
    14:23 modifié #5
    dans 1215084481:

    Le fait qu'ITMainWindowController soit le file's owner du nib ne devrait-il pas rendre possible l'appel de la méthode awakeFromNib: ?


    Non. awakeFromNib est appelé quand un objet instancié dans le .nib est "réveillé" (chargé en mémoire) lors de la lecture du .nib.

    dans 1215084481:

    Dailleur, awakeFromNib est bien exécutée puisque c'est le code qui est dedans qui fait planter l'appli, en l'occurence
    [self window];


    C'est donc qu'une autre instance ITMainWindowController est instancié dans le nib, et c'est son awakeFromNib qui est appelé.

    Le problème est de savoir lequel des 2 objets ITMainWindowController s'appropie la fenêtre (ce qui pourrait expliquer en partie pourquoi la fenêtre s'affiche, mais aussi pourquoi window ne retourne rien.


    dans 1215087150:

    Ce ne serait pas que ton fichier nib n'est pas déclaré dans les ressources de ton projet XCode ?


    Si la fenêtre apparait comme dit Flo, c'est que son .nib est bien chargé, donc il est bien trouvé, non ?
  • Philippe49Philippe49 Membre
    juillet 2008 modifié #6
    dans 1215089537:

    Non. awakeFromNib est appelé quand un objet instancié dans le .nib est "réveillé" (chargé en mémoire) lors de la lecture du .nib.

    Dans l'exemple ci-dessous, awakeFromNib est bien appelé après que l'application soit complètement lancée, car un nouveau nib est chargé.
    Cocoa ne charge les nib que si nécessaire, ce qui fait qu'en cas de double nib, seul le principal est chargé. En chargeant le second par [[ alloc] initWithNibname:], un message awakeFromNib est  envoyé aux instances créées par ce second nib.
  • Philippe49Philippe49 Membre
    juillet 2008 modifié #7
    dans 1215089537:

    dans 1215087150:

    Ce ne serait pas que ton fichier nib n'est pas déclaré dans les ressources de ton projet XCode ?


    Si la fenêtre apparait comme dit Flo, c'est que son .nib est bien chargé, donc il est bien trouvé, non ?


    J'ai compris que sa fenêtre ne s'ouvrait pas :

    dans 1215082378:

    Or lorsque je lance l'application, la window (connectée à  l'ITWindowController) ne s'affiche pas et le programme se fige sans ne rien afficher dans le log.


    mais si
    dans 1215082378:

    J'ai essayé de mettre la méthode awakeFromNib: en commentaire et de faire un NSlog() :

    <br />- (void) applicationDidFinishLaunching: (NSNotification*)notification<br />{<br />&nbsp;&nbsp; ...<br />	mainWindowController = [[ITMainWindowController alloc] initWithWindowNibName: @&quot;MainWindow&quot;];<br />	[mainWindowController showWindow: nil];<br /><br />&nbsp; &nbsp; NSLog(@&quot;%@&quot;, [mainWindowController window]);<br />&nbsp;&nbsp; ...<br />}<br />
    


    Le log affiche : (nil) et la fenêtre s'affiche  :-\\

    Pourtant la NSWindow de MainWindow.xib est bien connectée au ITMainWindowController également file's owner du xib


    Tu utilises l'outlet window de NSWindowController ou tu en crées un nouveau dans ta classe ?

  • FloFlo Membre
    juillet 2008 modifié #8
    Salut,


      J'ai compris que sa fenêtre ne s'ouvrait pas :


    En fait, la fenêtre ne s'ouvre pas quand je tente de faire [self window] dans awakeFromNib de ITMainWindowController (l'appli se fige sans message d'erreur dans le log). Lorsque que je ne tente pas d'accéder à  la fenêtre tout se lance sans problème.


      Ce ne serait pas que ton fichier nib n'est pas déclaré dans les ressources de ton projet   XCode ?


    En fait, pour ajouter un fichier nib, je fais toujours comme toi, je me mets sur le group ressource et j'ajoute par le menu add. J'ai rendu le nib localizable(English) comme celui qui est fourni de base quand on créer un projet coreData.


      Dans l'exemple ci-dessous, awakeFromNib est bien appelé après que l'application soit  complètement lancée


    Je confirme, la méthode awakFromNib de ITMainWindowController est bien lancée à  l'ouverture du nib. C'est l'acces à  [self window] (dans awakeFromNib) qui plante. Ce qui est marrant c'est que cette même méthode ([ITMainWindowController window]; ) renvoit nil dans applicationDidFinishLaunching: de l'AppDelegate.

    Donc deux cas :
    1 : si j'essaye d'accéder à  la window du WindowController dans son awakeFromNib, sa se fige.

    2 : si je n'essaye pas d'y accéder la METHODE AWAKEFROMNIB EST BIEN EXECUTEE et la fenêtre est affichée par la méthode [ITMainWindowController showWindow]; mais lorsque je fais [ITMainWindowController window]; sa me renvoit nil

    Dans les deux cas je ne peux pas accéder à  l'Outlet window du ITMainWindowController


      C'est donc qu'une autre instance ITMainWindowController est instancié dans le nib


    Je ne vois pas trop comment c'est possible, j'ai juste réglé dans IB la classe du File's owner sur ITMainWindowController dans le nib MainWindow.xib et connecté la window au bon Outlet.


      Tu utilises l'outlet window de NSWindowController ou tu en crées un nouveau dans ta classe ?


    J'utilise bien l'Outlet hérité de la super classe NSWindowController. dailleur j'ai essayé de contourner le problème en créant un nouvelle Outlet mais le résultat est le même...

    Je vais peutêtre me répéter, mais je suis sûr que ce que j'essaye de faire peut marcher puisque c'est ce qui se passe dans l'exemple SourceView fourni par Apple...

    Merci pour votre aide en tout cas...


  • Philippe49Philippe49 Membre
    14:23 modifié #9
    Compare avec l'exemple que j'ai posté, il marche ...
  • FloFlo Membre
    juillet 2008 modifié #10
    dans l'exemple que tu as posté, le nouveau nib est chargé lorsque l'on clique sur le bouton du premier. Moi je le charge dans la méthode applicationDidFinishLaunching:, est-ce que sa peut faire une différence ? A part ça, je ne vois aucune différence entre ce que tu as fais et ce que j'ai...je comprend pas...

    Sinon ton exemple représente bien la situation mais je ne peux pas le compiler, il semblerai que tu utilises une version d'Xcode plus récente que la mienne (pourtant j'ai la 3.0, tu dois avoir la béta 3.1 non ?)...

    Il me dit :
    Line Location Tool:0: Internal error occurred while creating dependency graph: ASSERTION FAILURE in /SourceCache/DevToolsBase/DevToolsBase-921/pbxcore/SpecificationTypes/XCCompilerSpecification.m:267 ...

  • FloFlo Membre
    14:23 modifié #11
    J'ai essayé de charger le second nib à  l'aide d'un boutton et une methode test style :

    <br /> - (IBAction) test: (id)sender<br />{<br />&nbsp; mainWindowController = [[ITMainWindowController alloc] initWithWindowNibName:&nbsp; @&quot;MainWindow&quot;];<br />	[mainWindowController showWindow: self];<br />}<br />
    


    mais ça ne change rien... L'appli se fige toujours quand je fais [self window] dans awakeFromNib de ITMainWindowController...  :'(

    Pourtant j'ai la même configuration que dans ton exemple... :o


  • FloFlo Membre
    juillet 2008 modifié #12
    Sa y est j'ai trouvé !  :adios!:

    Comme je l'ai dit tout à  l'heure j'ai mis le fichier mainWindow.xib en localizable(English) comme le fichier mainMenu.xib fourni de base avec un nouveau projet coreData pour qu'il soit dans le même répertoire English.Iproj/. Cette modification a empêchée la méthode initWithWindowNibName: @MainWindow.xib de trouver le XIB MainWindow.xib.

    C'est pour sa que ton exemple marchait et pas le mien... Maintenant est-ce que quelqu'un sait comment faire pour que sa marche malgré le fait que MainWindow.xib soit localizable ?

    Merci en tout cas pour l'aide apportée.

    Flo.
  • Philippe49Philippe49 Membre
    juillet 2008 modifié #13
    dans 1215094659:

    dans l'exemple que tu as posté, le nouveau nib est chargé lorsque l'on clique sur le bouton du premier. Moi je le charge dans la méthode applicationDidFinishLaunching:, est-ce que sa peut faire une différence ?

    aucune
    dans 1215094659:

    Sinon ton exemple représente bien la situation mais je ne peux pas le compiler, il semblerai que tu utilises une version d'Xcode plus récente que la mienne (pourtant j'ai la 3.0, tu dois avoir la béta 3.1 non ?)...

    XCode 3.1
    Pour le compiler sous XCode 3.0, sélectionne l'icone du projet, et dans le menu contextuel prend l'option get info.
    Tu trouve alors dans le panel General un pop-up de choix "project format".

    dans 1215098766:

    Comme je l'ai dit tout à  l'heure j'ai mis le fichier mainWindow.xib en localizable(English) comme le fichier mainMenu.xib fourni de base avec un nouveau projet coreData pour qu'il soit dans le même répertoire English.Iproj/. Cette modification a empêchée la méthode initWithWindowNibName: @MainWindow.xib de trouver le XIB MainWindow.xib.

    Je ne vois pas trop ce qui a pu se passer ... sans doute un lien mal établi entre la définition du projet et ton fichier nib.

    Pour la localisation, on conseille en général de s'en occuper en fin de réalisation du projet, cela évite des ennuis.

    J'ai essayé mon exemple localisé, il marche tout aussi bien.

     
  • FloFlo Membre
    14:23 modifié #14

      Je ne vois pas trop ce qui a pu se passer ... sans doute un lien mal établi entre la définition du projet et ton fichier nib.


    Ce que je ne comprends pas c'est que la fenêtre s'affichait quand je ne faisait pas d'accès genre [self window]; dans awwakeFromNib du ITMainWindowController. Seul l'accès à  la NSWindow par l'Outlet du NSWindowController ne marchait pas...

    J'ai remis le tout en localizable pour voir, et... ça marche...

    Les méandres de l'objective-c sont parfois bien insondables pour les petits amateurs de cacao... o:)
  • Philippe49Philippe49 Membre
    juillet 2008 modifié #15
    dans 1215102085:

    Ce que je ne comprends pas c'est que la fenêtre s'affichait quand je ne faisait pas d'accès genre [self window]; dans awwakeFromNib du ITMainWindowController. Seul l'accès à  la NSWindow par l'Outlet du NSWindowController ne marchait pas...

    Les méandres de l'objective-c sont parfois bien insondables pour les petits amateurs de cacao... o:)


    Le C, et donc l'Objective C, est extrêmement permissif, et ce n'est pas parce qu'on fait quelque chose d'une mauvaise manière que cela ne marche pas. Je ne sais pas pourquoi ton programme marchait, mais par contre, je ne suis pas surpris qu'il ait pu marcher ...

    Voici un petit exemple où on voit bien pourquoi cela peut marcher, alors que l'erreur est manifeste :


    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    int main (void)
    {
    char * p=malloc(50*sizeof(char));
    strcpy(p,"Bonjour le monde");
    free(p);
    puts(p);  // erreur manifeste
    return (0);
    }


    A l'exécution :
    % gcc pgm.c -o pgm -Wall -Wextra
    % pgm
    Bonjour le monde
    %



Connectez-vous ou Inscrivez-vous pour répondre.