Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Présentation du MVC

Compatible iOS 3. Cliquer pour en savoir plus sur les compatibilités.Compatible iOS 4. Cliquer pour en savoir plus sur les compatibilités.Compatible MacOS 10.4. Cliquer pour en savoir plus sur les compatibilités.Compatible MacOS 10.5. Cliquer pour en savoir plus sur les compatibilités.Compatible MacOS 10.6. Cliquer pour en savoir plus sur les compatibilités.Par AliGator (Olivier Halligon), le 09 mars 2011

Le but de cet article est d'introduire le concept de “MVC” à ceux qui ne le connaissent pas. En effet, ce design pattern est un élément incontournable de la programmation Cocoa

Prérequis

Pour pouvoir suivre ce tutoriel vous devez déjà avoir de bonnes notions dans le langage Objective-C. Avoir déjà effectué de préférence une première application Cocoa est un plus permettant de mieux faire le parallèle avec un exemple concret

Présentation

“MVC” est un acronyme qui signifie ”Model-View-Controller” (Modèle / Vue / Contrôleur en français donc).
C'est un design pattern (patron de conception), c'est à dire un concept d'architecture logicielle pour son application. Il permet d'avoir un code plus structuré, plus évolutif, plus maintenable, permettant de profiter de plusieurs mécanismes de Cocoa se basant également sur MVC, d'avoir de la persistence de données, et bien d'autres choses encore.

Qu'est ce que le MVC ?

Le principe de base du MVC c'est de séparer ses données (le “modèle”) de leur représentation (leur affichage dans une “vue”).


Le Modèle

Le “Modèle” est la représentation interne des données. Il permet comme son nom l'indique de modéliser les données que l'on va manipuler dans l'application. Le modèle représente les véritables données avec toutes les informations qu'elles véhiculent.

Par exemple, quand on est dans le Finder et que l'on manipule des fichiers et des données, le “Modèle” correspond à la description de ce que l'on appelle un “élément” (fichier ou dossier, représenté dans le modèle par une classe “Item” par exemple), c'est à dire quelque chose ayant un nom, une date de création, une date de modification, un créateur, des droits d'accès, un chemin d'accès… Et un élément pouvant être un fichier (représenté par exemple dans le modèle par une sous-classe FileItem de la classe Item) contenant des données (représentant le contenu du fichier)… ou être un dossier (représenté dans le modèle par exemple par une classe FolderItem, dérivant elle aussi de Item), contenant une liste de fichiers et/ou dossiers (donc d'objets de type Item).

La Vue

La “Vue” quant à elle est la représentation visuelle de ces données à l'écran.
Un même modèle peut avoir plusieurs représentations, tout comme dans le Finder on peut voir les fichiers et dossiers représentés soit par liste, soit par icônes, soit par colonnes, soit en Coverflow, etc…

La “Vue” est comme son nom l'indique ce que l'on voit à l'écran, la représentation sous forme de texte ou de dessin affiché à l'écran.
La Vue et le Modèle sont sensés être relativement indépendants, en particulier ne doivent pas forcément avoir à connaître comment sont organisés/codés chacune des parties, de sorte qu'un modèle puisse utiliser plusieurs vues indépendantes et qu'une vue puisse être réutilisée dans un autre projet pour représenter des données similaires mais utilisant un modèle différent.
Par exemple une vue représentant des éléments (avec un nom et une icône et une date) sous forme de liste peut servir pour le Finder à afficher des fichiers, mais on peut tout à fait imaginer réutiliser cette vue pour représenter d'autres choses, comme des évènements avec un nom et une date, ou des membres d'une famille avec un nom et une date de naissance, etc.

Le Contrôleur

Le contrôleur enfin, sert à faire l'interface entre le modèle et la vue.
En effet, puisque le modèle et la vue sont sensés être au maximum indépendants, le contrôleur sert à faire le lien pour faire communiquer l'un (M) avec l'autre (V)

Le contrôleur connaît à la fois le modèle et la vue. Quand la vue a besoin d'afficher un élément, elle demande au contrôleur de fournir telle information sur tel élément, par exemple le nom du 5e fichier du dossier courant. Le contrôleur sait comment demander cela au modèle, car il sait comment le modèle est organisé, et donc sait aller chercher l'information, l'extraire, éventuellement la formatter, puis la remonter à la vue.

Ainsi, si le modèle change un jour, et que par exemple les noms des éléments ne sont plus stockés directement dans la classe “Item” représentant un fichier ou un dossier, mais stockés sous la forme d'une liste de tous les noms des éléments dans un tableau du dossier parent (juste pour l'exemple), le contrôleur aura juste à s'adapter pour aller chercher l'information au nouvel endroit, mais la vue n'y verra que du feu et fonctionnera toujours pareil. Cela permet donc de conserver le principe d'abstraction si cher à la Programmation Orientée Objet.

L'avantage d'avoir l'acteur intermédiaire qu'est le Contrôleur est que du coup les modèles et les vues sont réutilisables et interchangeables. Si l'on veut rajouter une autre représentation pour un même modèle (rajouter la vue en colonne en plus de la vue par liste, ou la vue en icônes), le contrôleur sert d'adaptateur entre les deux (le M et le V).
Le contrôleur sert souvent de DataSource ou de Delegate aux objets de la vue, pour réceptionner les évènements clavier ou souris (OSX) ou tactiles (iOS). Il peut servir également à formater les données (mise en forme) avant de les remonter à la vue. Sous iOS, la classe UIViewController est largement utilisée pour servir de contrôleur. Un UIViewController a entre autres une propriété “view” qui pointe sur la vue que le UIViewController contrôle, libre ensuite au développeur de rajouter ce qu'il faut pour récupérer son modèle de données et le présenter à la vue quand cette dernière demande des informations à afficher.

MVC par l'exemple

Imaginons une application comme l'appli “Contacts” sur iPhone, qui est donc un carnet d'adresses listant des personnes et des informations associées

Le but du MVC va être de séparer dans l'application la partie “Modèle” et la partie “Vue”.

- Le modèle (M) pourra être représenté par un NSArray d'objets qui sont des instances d'une classe qu'on appellera par exemple “Contact”. Chaque objet “Contact” contenant une NSString pour le nom de la personne et une NSString pour le prénom, et d'autres NSString pour l'adresse ou d'autres informations, une NSDate pour la date de naissance de la personne, etc.
C'est donc la représentation interne de nos données, que l'on va manipuler en interne. Si on veut ensuite rechercher tous les contacts dont le nom commence par “A”, on va fouiller dans le NSArray d'objets Contact pour les trouver.

- D'un autre côté, on a les vues (V) donc les représentations de ces contacts. On peut représenter dans l'application une liste de tous les noms et prénoms de nos contacts, on peut aussi afficher une fiche affichant le détail d'un contact donné, on pourrait même imaginer je sais pas par exemple une vue qui affiche la liste des contacts en affichant une grille de leurs photo/avatar avec leur nom en dessous (façon écran d'accueil de l'iPhone qui présente les applis et leur nom en dessous) plutôt qu'une liste défilante, etc. Toutes ces “vues”, ces “représentations” utilisent le même modèle, la même liste de contacts. Mais elles représentent les données de ce modèle de façon différente à l'écran.

- Le contrôleur (C) fait le “pont” entre le modèle et la vue, permettant à la vue d'interroger le modèle : la vue demande ainsi au contrôleur “retourne moi le nom du contact n°8 j'en ai besoin” et le contrôleur sachant comment est organisé le modèle sait l'interroger et donc récupérer cette information et la retourner à la vue.

Si un jour on veut rajouter une autre représentation de nos contacts, par exemple une représentation sous forme de “coverflow” de ces contacts, il suffit de rajouter une vue qui gère ce type d'affichage.
Si un jour on modifie le “backend”, donc la façon dont sont organisées les données en interne, par exemple si on n'utilise plus un NSArray d'objets Contacts, mais un NSDictionary qui à chaque nom associe un objet Contact, ou encore si on stocke l'adresse sous la forme disons d'un dictionnaire avec les clés “numéro”, “rue”, “code postal”, “ville” plutôt que sous la forme d'une simple NSString… malgré tout on n'aura pas à changer nos vues pour autant : juste à adapter le Contrôleur pour coller au nouveau modèle et qu'il sache chercher les informations aux nouveaux emplacements.

L'avantage également de ce type d'architecture, c'est que c'est flexible au-delà du projet de départ: si on a implémenté correctement la vue qui affiche nos contacts façon Coverflow, on devrait pouvoir très facilement réutiliser cette même vue dans un autre projet pour afficher façon Coverflow d'autres type de données, par exemple si on a à côté un autre projet qui lui manipule des albums musicaux et que l'on veut afficher les pochettes des albums, on devrait pouvoir réutiliser cette vue coverflow!

Le contrôleur permet également éventuellement de formatter des données avant de les retourner à la Vue. Par exemple si dans notre modèle nous avons pour chaque contact une NSDate représentant la date de naissance de l'utilisateur, dans tout le modèle ça restera une date, mais quand la vue va en avoir besoin, on va formatter cette date pour l'affichage. Par exemple écrire plutôt “Lundi 1er mars 2011” ou préférer écrire “01/03/2011” ou “Le 1er mars” ou “il y a 2 jours”… pourtant côté modèle ça restera la même date que l'on stoque, mais sa présentation différera.

Conclusion

Le MVC permet de proprement séparer les objets manipulés, contenant toutes les données définissant ces objets, les propriétés, etc… de leur représentation visuelle et de toute la mécanique de présentation.
Ce Design Pattern se retrouve un peu partout dans Cocoa, par exemple dans les UITableViews sous iOS.

Le MVC est un principe relativement vaste, qui peut être appliqué à beaucoup de choses et n'est pas restrictif. Certains projets peuvent ainsi être vus sous la forme d'un MVC imbriqué dans un MVC (la partie “persistence des données” pouvant elle-même être vue comme du MVC où le M est le fichier contenant les données et le V la représentation en mémoire (sous forme de classes et d'instances d'objet Objective-C) dans l'application du modèle de données…
Il ne faut pas hésiter à l'utiliser, le principe de base étant de séparer dans tous les cas les données et le modèle (partie métier) de leur représentation visuelle.

Pour aller plus loin

Comme toujours, n'hésitez pas à consulter la documentation Apple : elle est vraiment plus que riche et fournie, et rares sont les sujets qu'elle ne couvre pas.
Ainsi vous trouverez Sur la DevPedia Apple une page dédiée au MVC ainsi que Le paragraphe dans le Cocoa Fundamentals Guide sur le sujet (dont le lien est d'ailleurs donné dans la DevPedia également)