Differences NSWindow / NSWindowController ?
Adau
Membre
Bonjour,
Après avoir bien fini le livre de notre cher Aaron, il y a toujours un point sur lequel je bute:
Quels sont les differences entre les classes NSWindow et NSWindowController ?
Ces deux classes permettent d'afficher des fenêtres. Deux instances de ces classes qui recoivent "showWindow:self" affichent la fenêtre qui leur est associé.
En regardant la documentation, je n'arrive pas trop à comprendre les subtilités.
Au passage, j'ai un peu la même question pour NSView (dont je comprend très bien son rôleà et NSViewController (dont je comprend rien).
Merci d'avance !
Adau
Après avoir bien fini le livre de notre cher Aaron, il y a toujours un point sur lequel je bute:
Quels sont les differences entre les classes NSWindow et NSWindowController ?
Ces deux classes permettent d'afficher des fenêtres. Deux instances de ces classes qui recoivent "showWindow:self" affichent la fenêtre qui leur est associé.
En regardant la documentation, je n'arrive pas trop à comprendre les subtilités.
Au passage, j'ai un peu la même question pour NSView (dont je comprend très bien son rôleà et NSViewController (dont je comprend rien).
Merci d'avance !
Adau
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
La Window est un objet graphique, le WindowController en décide le comportement.
Mais dans quels cas utiliser un NSWindowController ou un NSWindow ?
Après, il faut se poser la question de la distribution des rôles dans ton programme. Pour des programmes relativement simples, cela ne pose pas trop de problème de faire gérer la fenêtre au contrôleur général de l'application, mais pour des programmes plus complexes, ou pour des classes que l'on veut réutilisables (un inspecteur, un panel de choix, une vue au design spécialisé, ...), on peut faire, comme dans le ch 29 de Hillegass, un découpage en
- un fichier xib pour le design de la vue (resp fenêtre)
- une classe pour le controller représenté par le File's Owner du xib, et créé par ailleurs dans le code
- une classe pour la vue (et son contenu) que l'on ajoute au besoin sur la fenêtre principale.
Tu utilises toujours les deux.
Souvent, un NSWindowController est créé sans que tu t'en rendes compte. Par contre, passer par un NSWindowController est le seul moyen de charger une fenêtre depuis un .nib.
Ha ? Quand je fais ça dans mon controller perso (qui n'hérite pas de NSWindowController) ça passe quand même par un NSWindowController ?
Il me semble que par cette methode mon controller devient le file owner du nib qui contient un NSWindow et peut la gérer sans passer par un NSWindowController...
Je réitère le conseil de Philippe49. Et même j'irai plus loin en disant qu'il vaut mieux utiliser un XIB par fenêtre et par vue interchangeable avec les contrôleurs correspondant (NSWindowController pour un xib de NSWindow et NSViewController par xib de NSView).
Pour la gestion des différents éléments graphiques c'est beaucoup plus simple, plus efficace et plus clair. Et je conseille même de faire des allocations/désallocations à la volée, c'est-à -dire que tu alloues le contrôleur et instancies le XIB seulement au moment où il va être afficher, et quand il ne sera plus affiché, tu le supprimes complètement, ça peut sembler coûteux en mémoire mais ce n'est pas vraiment quelque chose de gênant de nos jours, surtout que cette mémoire est recyclée.
Alors vous pouvez quand même vous amusez à stocker les contrôleurs au fur et à mesure qu'ils sont chargés, mais la gestion des objets en mémoire devient alors un vrai casse-tête. Personnellement, j'ai vite abandonné cette idée.
Pour ce qui est des NSViewController, je précise un peu. Quand on a par exemple une fenêtre de préférences avec plusieurs panneaux, une bonne technique est de créer un XIB pour une fenêtre avec un NSWindowController comme file's owner, la fenêtre aura une toolbar par exemple, mais la contentView sera complètement vide.
Au lieu de définir une vue par panneau dans le même XIB et de les mettre dans liste des objets de premier niveau... Une bonne pratique est de créer un XIB par NSView, chaque XIB représentera un panneau de préférences, et chaque XIB contiendra un file's owner de type NSViewController (ou d'une sous classe).
Avec cette architecture, le NSWindowController des préférences fait la permutation des vues à la demande. à‰tant donné qu'il doit aussi gérer une NSToolbar, j'ai personnellement opté pour un dictionaire contenant pour chaque NSToolbarItem le nom de l'item, le nom de l'icône, et le nom du XIB à chargé. Quand on clique sur un item, je sélectionne dans le dictionaire l'objet correspondant à l'identifiant de l'item et je charge les infos correspondantes. Je ne conserve dans les ivars de mon NSWindowController que le NSViewController affiché, et j'alloue/supprime à chaque changement d'onglet.
Mouaip sur ce coup je trouve ça un peu débile l'histoire de charger un NSViewController quand tu changes d'item sur la toolbar.. Autant relâcher carrément le NSWindowController des prefs une fois que la fenêtre est fermée?
Si la fenêtre n'est ouverte qu'une seule fois par exécution, la mémoire qu'elle utilise sera disponible pour le reste de l'application...
Il faut d'abord mettre en priorité la clarté et la simplicité du code, et ensuite t'optimise.
En gros, si je veux afficher une fenêtre, disons la fenêtre de préférences. Dans mon AppController, je mets une variable PreferenceController d'une sous classe d'un NSWindowController que j'aurai créé. Cette sous-classe jouera le rôle d'un Controlleur "normale" d'une application mais juste pour la partie préférence.
J'affiche mon fichier xib en invoquant la méthode [instancePreferenceController showWindow:self], le fichier xib ayant pour File's Owner la classe PreferenceController.
Ce qui me semble bizzare, c'est que si la sous classe n'est plus un NSWindowsController mais juste un NSWindow, ca marche aussi, de la même manière.
Non ça ne sera pas pareil, tu ne pourras pas créer un "Preferences.xib"... en remplaçant NSWindowController par NSWindow, tu initialises simplement une fenêtre... ce qui est assez idiot si on veut faire des préférences.
NSWindowController va te permettre de gérer ta NSWindow dans un "Preferences.xib". Ce meme NSWindowController pourra gérer les différents éléments qui composent la fenêtre.
En gros c'est comme si tu avais un MainMenu + AppController bis.
Dans ce cas là , quel est le rôle de la classe NSWindow ou de ses sous-classes créées par nos soins ?
Ensuite, la class NSWindow c'est l'objet graphique "fenêtre", les instances de NSWindow ce sont les objets qui s'affichent à l'écran, c'est elle qui reçoit les événements et les transmets à ses vues, c'est elle qui se ferme ou s'agrandit quand tu appuies sur ses boutons en haut à gauche.
Alors que NSWindowController est un objet non-graphique conçu pour contrôler la fenêtre, et cette classe-là est typiquement conçue pour être sous-classée pour contenir la logique de ton application.
On peut définir le sous-classage par remplacement des méthodes déjà existantes de la classe afin de les améliorer ou de modifier son comportement. Mais il peut se définir aussi par l'ajout de méthodes.
Imaginons que tu veuilles faire une fenêtre transparente, tu devras sous classer NSWindow et overrider le "init...." de la fenêtre. Imaginons aussi que tu veuilles rajouter une sous-vue à la "contentView" de ta fenêtre (la contentView d'une NSWindow c'est simplement la vue de la fenêtre comme son nom l'indique, mais sans les Toolbar, bar de titre etc...). Il suffira alors de faire [[maFenetre contentView] addSubview:otherView]; .. bon soit c'est la meilleure solution... mais vu que tu as déjà sous-classé la fenêtre en question autant en profiter pour lui rajouter des méthodes? tu rajoutes donc -(void)addSubview:(NSView*)view; dans le header de la sous-classe de NSWindow, puis dans le fichier implémentation tu fais appel à sa contentView :
ça sert à rien, mais dans ton AppController ça t'éviteras de faire appel à la "contentView" vu que la sous-classe de la fenêtre se chargera de ça.. suffira juste de faire [myWindow addSubview:otherView];
Sous-classer n'a vraiment de sens que si tu veux changer le comportement de la classe, en tout cas dans le cas des classes normales. Par exemple, NSPanel, sous-classe de NSWindow, change le comportement de NSWindow en n'acceptant jamais de devenir la mainWindow de l'application, les instances de cette classe ne seront jamais plus que des keyWindow.
Ces sheets ne sont instanciées à partir d'un xib qu'à la première demande via la méthode :
Est-ce vraiment nécessaire de passer par un NSWindowController pour chacune des sheets ou alors vaut-il mieux réserver cette classe pour les fenêtres (exceptées les sheets) et les NSView ?
à la manière d'un UIAlertView, tu peux simplement le créer lorsque tu en a besoin puis le release une fois que tu reçois la delegate qui annonce la fin du sheet.
Toi tu ferais un release sur la sheet quand on la ferme ? C'est pas un peu lourd de recharger le xib à chaque fois qu'on veut s'en servir ?
Sinon on passe par un NSWindowController ou pas ?