MVC et gestion/accès aux NSUserDefaults

muqaddarmuqaddar Administrateur
mai 2013 modifié dans API AppKit #1

Salut,


 


J'ai pris l'habitude d'appeler mes NSUserDefaults (préférences) depuis les contrôleurs, pour les envoyer si j'en ai besoin en paramètre d'une méthode au modèle.


 


En effet, ça me paraà®t plus logique en MVC de faire comme ceci, plutôt que de chercher les NSUserDefaults directement depuis le modèle. Ai-je raison ?


 


Donc en gros, je ne charge aucun NSUserDefault dans la couche modèle.


 


Par exemple, les propriétés login/password du modèle "NetworkEngine" qui se connecte au réseau sont envoyés en paramètre d'une méthode plutôt que d'être appelé directement depuis la classe NetworkEngine.


Réponses

  • AliGatorAliGator Membre, Modérateur

    Cela me parait également logique dans l'ensemble.


     


    En fait ce qu'ici tu appelles "Modèle", moi je l'appelle la couche "Services".


     - La couche "Modèle" normalement n'a aucune d'intelligence (ou très peu), son but est juste de représenter des objets (un Vin, un Casier...)


     - Ce que j'appelle la couche "Services" met à  disposition des services utilisables par le reste de l'application dans son ensemble, un peu partout. Vu le nom, ta classe "NetworkEngine" me semble plutôt faire partie de cette catégorie, une couche dédiée pour gérer toutes les interactions avec le réseau.


     


     - Dans une couche Services comme "NetworkEngine", le but est de la rendre le plus générique possible, donc de passer login et password en paramètre à  cette couche, et c'est l'appelant qui ira les chercher dans les NSUserDefaults, cela me semble cohérent.


     - Par contre, si la couche Services a besoin d'éléments internes pérennes, cela ne me semble pas déconnant qu'elle appelle parfois elle aussi directement les NSUserDefaults. Par exemple si une fois que ton NetworkEngine a passé la phase d'autentification (en se connectant à  ton WebService via un login/pass) il reçoit un token en retour, et qu'il doit réutiliser ce token ensuite pour les requêtes suivantes pour prouver qu'il est logué, ça a du sens que ce soit ton NetworkEngine qui stocke ce token dans les NSUserDefaults (pour les garder mm si l'appli est quittée et relancée) et le réutilise tout seul en interne : l'extérieur de NetworkEngine (les utilisateurs de cette classe) n'ont pas à  connaà®tre le mécanisme interne de fonctionnement, que ce soit avec un token ou autre, et n'ont pas à  gérer ça.


     


    Donc pour moi ça ne dépend pas tant de savoir si ta classe est dans la partie Modèle ou Controlleur ou Services ou autre, mais plutôt d'une logique d'usage de savoir si tu exposes des paramètres à  l'extérieur (comme login/pass) car l'extérieur a besoin de pouvoir passer ces paramètres et que cela fait plus générique (et du coup c'est à  l'extérieur d'aller chercher ces valeurs dans les NSUserDefaults pour les proposer par défaut dans le formulaire de connexion ou autre), ou si tu as des éléments internes à  garder dans les NSUserDefaults mais qui n'ont pas de raison d'être exposés à  l'extérieur (comme un token interne). C'est plutôt une question de faire une API cohérente et logique et savoir ce que tu exposes à  l'extérieur plutôt que de savoir dans quelle couche tu es.


  • samirsamir Membre

    Hello,


     


    j'ai une question et une remarque a ajouter à  ce poste. Moi généralement je créer une classe dédié pour tous ce qui token par exemple : UserInfo et cette classe qui sauvegarder et récupérer toutes les infos de NSUserDefaults par exemple NetworkEngine n'a pas a dupliquer du code pour stocker ou bien récupérer le token : c'est le role de UserInfo dans mon cas .


     


    1. Une question  : Par exemple dans une application avec une classe service NetworkEngine, le parsing du retours ce fait dans la meme classe ou bien ça vas etre un objet spécial parsing ou bien on retourne a l'appelant le JSON/XML et c'est a lui de se débrouiller. 


     


    2. Une autre question :)  : la meme que la 1) mais pour le cas des retours d'erreurs, est-ce que vous créer des classe spéciale pour la gestion d'erreur et alertes ?


     


    PS : Désolé pour me meler avec des nouvelles questions dans ce post, mais je trouve que ça une relation avec le MVC.


     


    Merci

  • muqaddarmuqaddar Administrateur
    mai 2013 modifié #4

    @Ali. Mon exemple tait mal choisi, même si j'ai compris ta logique. Donc, je vais aller plus loin, avec un autre exemple. Nous avons une classe modèle "Voiture" avec une propriété "Couleur". L'application retient la dernière couleur choisie à  chaque fois qu'une voiture est créée, dans le UserDefaults "LastColor", car il y a de forte chance que la Voiture suivante ait la même couleur dans la chaà®ne des événements, et qu'ainsi on n'ait pas besoin de sélectionner la couleur pour la voiture suivante.


     


    Donc moi, j'irai jusqu'à  faire depuis le controller :



    [[Voiture alloc] initWithColor:[defaults objectForKey:LastColor]];

    plutôt que depuis le controller :



    [[Voiture alloc] init];

     et dans le -(id)init du modèle Voiture: 



    self.color = [defaults objectForKey:LastColor]

    Pourtant le UserSettings ne retient bien qu'une valeur de modèle ici... mais je trouve cela plus logique. Le modèle doit être au maximum dissocié et indépendant de tels paramètres.


  • AliGatorAliGator Membre, Modérateur

    @Ali. Mon exemple tait mal choisi, même si j'ai compris ta logique. Donc, je vais aller plus loin, avec un autre exemple. Nous avons une classe modèle "Voiture" avec une propriété "Couleur". L'application retient la dernière couleur choisie à  chaque fois qu'une voiture est créée, dans le UserDefaults "LastColor", car il y a de forte chance que la Voiture suivante ait la même couleur dans la chaà®ne des événements, et qu'ainsi on n'ait pas besoin de sélectionner la couleur pour la voiture suivante.

    Tu as répondu a ta question en exposant ton problème.


    Ce n'est pas une caractéristique du modèle (de l'objet Voiture) que de mémoriser la couleur de la voiture précédente. Chaque objet Voiture doit être indépendant, et pouvoir fonctionner quelles que soit les règles métier de fonctionnement de ton appli que tu mets derrière.

    Le fait que tu veuilles mémoriser la dernier couleur utilisée lorsque tu as saisie la dernière voiture, c'est une caractéristique de ton Controlleur de saisie des données qui permet de créer une nouvelle voiture.

    Le plus simple est de se poser la question suivante : et si je voulais réutiliser ma classe modèle Voiture dans une autre application, est-ce normal que je force ce comportement de réutiliser la dernière couleur ? Non, c'est parce que ce sont des préférences de saisie (et donc pour faciliter l'UI) que tu veux ce comportement, ce n'est pas une caractéristique du modèle.

    Et les objets modelés ne devraient pas dépendre de l'ordre dans lesquels on les crée (là  si tu fais juste un init sur Voiture qui reprend la LastColor ça veut dire que si tu crées une voiture rouge, puis une bleue, puis une avec juste init, la dernière sera bleue, alors que si tu avais inversé les 2 premières créations cela n'aurait pas donné le même résultat... cela va a l'encontre d'un bon test unitaire qui doit être déterministe.


    Donc pour ton cas, ce que tu mémorises ces la dernière valeur sélectionnée par l'utilisateur dans le UIPickerView permettant de choisir la couleur, parce que tu veux mémoriser les paramètres de saisie pour éviter à  l'utilisateur d'avoir à  rechoisir cela dans ton UI. C'est bien un truc lié à  l'UI et pour faciliter la saisie utilisateur. En aucun cas ce comportement ne fait partie du modèle et définit le comportement d'une voiture et donc en aucun cas cette logique de proposer par défaut la dernière valeur utilisée doit être intégrée dans une logique côté Modèle !!
  • muqaddarmuqaddar Administrateur

    Je suis donc entièrement d'accord avec toi.


    Mais je voulais quand-même avoir un retour d'expérience. :)


     


    Je n'ai jamais eu de cours de théorie sur le MVC ni lu de livre, donc j'essaie de penser "logique" et dissociation des taches.


    D'ailleurs, j'ai plein de questions en stock de ce genre-là . Evidemment, ce n'est pas ça qui empêche un programme Cocoa de fonctionner. :-)


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