Faire un code propre MVC en Objective-C
Après avoir lu des dizaines de tutoriaux en ligne, et connaissant plusieurs langages, la première chose que je me suis dit c'est qu'ils codent comme des gros dégeulasses en balançant tout dans le AppDelegate.m. Et que pour un gros programme, c'est comme si on faisait tout dans la méthode main (en langage C). C'est immonde.
Ma question est donc la suivante (elle est assez générale) : Comment faire un code propre ?
Normalement en MVC on balance tout dans le controller qui gère la fenêtre.
Dans vos programmes, la méthode didFinishLaunchingWithOptions est quasiment vide ou pas ?
A quoi vous sert réellement le AppDelegate ?
Normalement il ne doit servir qu'à des actions précisent bien spécifées dans le fichier : Application Terminée, Application a terminée son lancement, etc.
Je me trompe ?
Merci de donner votre point de vue, en m'expliquant comment vous catégorisez vos fichiers.
Réponses
Le problème c'est que ceux qui font des tutoriaux sont rarement des gens qui vivent de leurs développements. Donc la maintenabilité est le moindre de leur besoin.
Perso sous OS X, en règle générale j'ai un contrôleur principal (qui est aussi de manière assez logique le delegate de mon App et de ma fenêtre mère pour un app Desktop). A partir de là , j'ai deux approches pour structurer:
- usage de "sous contrôleurs" (hiérarchisés de manière pyramidale si la complexité du projet le justifie) pour de gros morceaux liés à la gestion de parties métier bien identifiées.
- usage de catégories liées à mon contrôleur principal pour des morceaux plus simplistes mais pour autant facilement détachables.
Après sous iOS, l'approche peut même être poussée plus loin. La navigation se faisant par le biais de multiples vues, on a souvent un contrôleur par vue avec un contrôleur de navigation qui chapeaute l'ensemble avec un mécanisme du push/pop. Chaque contrôleur se contente alors de gérer les interactions avec la vue qui lui est affectée et le contrôleur de navigation s'occupe de la hiérarchie des vues/contrôleurs. Que les experts iOS me contredisent si j'ai écris une ânerie.
A faire ce pour quoi il a été prévu à l'origine : juste être le délégué de l'application
Exactement.
Non, tu as tout bon Les tutos que tu cites et as pu voir sur la toile sont codés comme les pieds (sans doute parce que leur but c'est de te montrer rapidement comment arriver à un résultat, plutôt que comment le faire proprement.
Mais rassures-toi, tu as tout résumé et tout bien compris : le vrai MVC, tel qu'on l'utilise dans nos applis de tous les jours, est comme tu le décris : quasiment rien dans le AppDelegate à part ce qui est nécessaire pour gérer le lancement/la fin de l'appli, ou ce genre de choses, et ce qui est nécessaire pour gérer la fenêtre et ses interactions dans un Controlleur. Je te rassure c'est bien comme ça qu'on fait, contrairement à ce que semblent montrer tes tutos !
Plus crade, tu meurs !
Il y a quelques années, quand j'ai commencé le dev iPhone en tant que stagiaire, un collègue m'avait conseillé cette bonne pratique.
Aujourd'hui les personnes en charge de la maintenance de l'application en souffre énormément. Dès qu'on me prononce le nom de l'application j'ai tout de suite pleins de remords, et je fuis pour pas que je sois son prochain mainteneur.
Du coup, qui instance les classes modèle ? Les view controllers ?
Si le modèle est global, on l'instancie dans le VC global ?
Sinon si tu as un modèle à instancier soit tu fais une sharedInstance pour le manipuler et y accéder de n'importe où, soit tu le passes de proche en proche de VC en VC (il y a débat entre ces 2 solutions, mais dans tous les cas il ne faut pas avoir à référencer l'AppDelegate depuis les autres classes à chaque fois que tu as besoin de ton modèle, sinon c'est que ton code est très mal cloisonné)
Moi pour l'instant mes fichiers sont déclarés comme suit :
- Un dossier Modèle pour mon modèle de données
- Un dossier Controller pour mes ViewController
Le problème c'est que je me retrouve avec des fichiers qui ne sont pas des ViewController dans ce dossier. Je pense spécifiquement au fichier nommé ProductViewCell que j'ai créé et qui est une partie spécifique du TableViewController qui gère mes "Products"
Comment ranger ces fichiers de manière plus propre ? Je refléchis encore à comment nommer ce nouveau dossier franchement.
Et j'ai une question concernant le navigationController. A quoi il sert exactement ?
Plusieurs objets le mettent en place systématiquement. Comme par exemple quand on ajoute une vue qui contient des onglets.
Un navigationController est-il obligatoirement le point d'entrée de notre application ?
Tout ça se discute, et ce n'est pas d'une importance vitale. En gros UITableCellView hérite de UIView, donc c'est une vue. Pourtant, en général, un type de cellule n'est utilisé que dans une seule table; ainsi ça a plus de sens de grouper la cellule avec le TableViewController qui l'utilise.
Tu verras par la suite que comme les TableViewControllers deviennent vite énormes, la tendance actuelle est de déporter la logique dans la cellule, qui devient alors un contrôleur...
Il gère une pile de view controllers. Il y a une commande Push pour empiler, et une commande Pop pour dépiler.
Seul le view controller en haut de la pile apparaà®t. Une UINavigationBar affiche le titre du contrôleur courant et une flèche pour dépiler.
Non, par exemple, si tu as des onglets (UITabBarController), chaque onglet contient un view controller différent. Il se trouve que ces view controllers sont souvent des navigation controllers, pour permettre de se promener dans l'arborescence de chaque onglet, mais tu auras bien une pile par onglet.
à lire absolument :
ViewController Programming Guide for iOS
C'est souvent des questions bidons qu'ont les développeurs qui viennent d'autres langages, mais en réalité ce sont là ou se situe les différences entre les langages et surtout c'est là qu'on différencie un projet qui fonctionne, d'un projet optimisé et maitrisé car le développeur sait exactement ce qu'il fait à n'importe quel moment!
Merci pour le lien samir, je viens de le lire et il est très bien expliqué !
Donc ca veut dire qu'un NavigationController contient toutes les View dans lesquels il peut naviguer, empilée et qu'on y accède à partir d'un ObjectIndex (de mémoire).
Est-ce que c'est quand même fait de manière intelligente, c'est à dire qu'il ne charge que ce dont il a besoin au moment ou il en a besoin ? Parce que si tout est empilé, ca fait peur au niveau de l'utilisation mémoire
Donc Céroce, ton dossier Controller contient tes ViewController, et ton dossier View contient le contenu de tes ViewController, comme par exemple une TableViewCell ?
Dans le dossier Vues, je mets mes éventuelles sous-classes de UIView et UIControl, qui seront utilisées un peu partout dans l'appli.
Tu l'instancies ou ton modèle toi ? Dans le controller de la première vue ?
EDIT : C'est pour relancer le débat entre la sharedInstance et le passage à chaque VC
Ok merci de ta réponse
Non, dans l'AppDelegate. Puisque c'est lui qui instancie les contrôleurs "racine", alors il y a forcément accès. La différence, c'est que ce sont les contrôleurs qui passent ensuite à leurs enfants ce dont ils ont besoin (pas forcément tout le modèle). On identifie alors clairement les dépendances entre classes.