Storyboards, ViewControllers & Swift (ou OS X the iOS-way)

PyrohPyroh Membre
juillet 2014 modifié dans Objective-C, Swift, C, C++ #1
Dans la mesure où je code en Swift et que je vais parler de framework encore en beta j'ai pensé que c'était le meilleur endroit du forum ou démarrer ce topic. Qu'un modérateur le déplace si jamais il s'avère que ce topic a sa place ailleurs.
 
Je travaille depuis quelques jours à  convertir Uncia en Swift sous 10.10. 
Je reprends tout de zéro (sauf la collection de données relative aux tailles de papier) alors je m'amuse à  redéfinir toute la chaà®ne MVC en Swift et à  me frotter aux Storyboards sous OSX. 
Le soucis c'est que c'est tout nouveau pour moi ne faisant pas de dev iOS, alors ma question est la suivante :
 
J'ai un ViewController disons, racine, que j'ai appelé MasterViewController. Il s'occupe entre autres choses de loader dynamiquement la liste des tailles de papier. J'ai donc une propriété itemCollection qui est un Array<PresetItemCollection>. J'aimerai beaucoup que cet Array soit disponible dans un autre ViewController à  quelques segue de là ...
Quelle est alors la meilleure solution :
  • Passer une référence de MasterViewController de ViewController en ViewController ? (Est-ce une bonne technique de manière générale ?)
  • Instancier itemCollection directement dans le ViewController qui va l'utiliser et le loader à  chaque fois ? (Je ne sais rien d'un éventuel caching effectué par l'OS sur les ViewController)
  • itemCollection ne sera pas modifié au cours de l'exécution, mieux vaudrait alors en faire une propriété de classe ? (Elles fonctionnent maintenant en beta 3 ?)
  • Une SharedInstance ? (J'ai vu que ça se faisait pas mal sous iOS)
Bref j'ai besoin de l'avis des bons dev iOS qu'il y a en nombre ici. Toute suggestion est la bienvenue  :)

Réponses

  • C'est quoi PresetItemCollection ?


  • C'est une classe qui contient des infos structurées. (ça va sûrement se transformer en structure je pense j'ai pas encore pris le pli)

    En gros ça n'est pas super important.
  • Cela peut-etre considéré comme du model.

    Tu peux faire un fournisseur de PresetItemCollection (pourquoi Collection ?) qui sera chargé de créer, relire, téléchargé ou autre les item.


    Le plus simple est de faire un singleton (ce que tu appelles sharedInstance) (http://stackoverflow.com/questions/24024549/dispatch-once-singleton-model-in-swift) pour l'access à  ce "PresetItemProvider".
  • Effectivement ça fonctionne comme il faut merci.

    Manque plus qu'Apple implémente les variables de classe et on pourrat se passer du tour de passe-passe à  base de struct...


    Comment on ferait dans le cas d'une instance de sous-classe de NSDocument ? Je peux pas faire un singleton avec une telle chose.

    Sans bindings je suis un peu perdu...
  • samirsamir Membre
    juillet 2014 modifié #6

    Hello,


     


    Moi j'éviterai l'utilisation des singletons dans ton cas. A mon avis il faut juste passer tes objet à  la construction/initialisation des autres classes, soit avec des custom init ou bien en utilisant des properties. 


     


    J'utilise des singleton pour des objet qui offre plus un service que un état. Comme une classe qui fait les requêtes réseaux,.... En gros j'évite les états globaux et un singleton est le mal pour ça.



    @interface MyController1 
    - (instancetype)initWithDocument:(MySousClasse *)document;
    @end
  • Dans le cas d'un Document, effectivement samir a raison. Plus généralement dans le cas d'une app OSX, il a raison.


    Mais en pratique beaucoup d'app (surtout sur iOS) prennent leur données d'une seule source à  la fois donc le singleton peut convenir.


     


     


    Il faut quand même éviter si c'est possible de passer tout le document de proche en proche pour éviter les adhérences inutiles.


    Il faut plutôt essayer de passer juste le minimum, par exemple, un tableau des presets à  afficher plutôt que tout le document.


    Ou alors passer  le document mais sous la forme d'un protocol spécialisé plutôt qu'un dérivé de NSDocument.



    @interface MyDocument : NSDocument <PresetProviderProtocol>
    ...
    @end
    @interface MyController
    -(instancetype) initWithPresetProvider:(id<PresetProviderProtocol>)provider
    @end

    Tu traduiras en swift...

  • Merci pour ces conseils, je les ai utilisés pour faire avancer ma réflexion. J'ai décidé que la liste des "presets" devait être gérée directement par le viewController qui va la manipuler.


     


    J'ai aussi réfléchi à  un design mais je ne sais pas trop si c'est une bonne idée. 


     


    L'idée est la suivante: un singleton qui contient les références (weak pour éviter les retain cycle) à  tous les objets utiles. ça peut être une multitudes de choses comme un context CoreData ou un NSUndoManager pour ne citer que des cas génériques.


     


    Une sorte de passe-plat global. Maintenant je sais que c'est une chose qui est souvent source de polémique et j'aimerai savoir à  quoi je m'expose en utilisant un tel pattern. Concrètement, si on reste raisonnable au niveau du nombre des propriétés du singleton et qu'on évite de l'utiliser dans un programme multi-threadé je vois pas en quoi cela constituerait une hérésie.


     


    Qu'en pensez-vous ? 




  •  


    Une sorte de passe-plat global. Maintenant je sais que c'est une chose qui est souvent source de polémique




    Le sujet de polémique, c'est que souvent le passe-plat en question c'est le appDelegate, qui devient une sorte de fourre-tout alors que ce n'est pas son rôle. Pour les shared instances c'est moins sujet à  opprobre...



  • L'idée est la suivante: un singleton qui contient les références (weak pour éviter les retain cycle) à  tous les objets utiles.




     


    Mais de coup c'est qui le responsable de la durée de vie de ces objets ?


     


     




    Une sorte de passe-plat global. 




     


    Les problèmes que je vois personnellement sont les suivants :


     


    1. Tu brises le principe de l'unique responsabilité. Ton singleton vas se retrouver avec pleines de choses qui ne sont pas forcément liées, donc un code difficile à  maintenir, qui vas changer beaucoup donc risque de bugs souvent.


     


    2. Tu vas créer pleines de dépendances cachées. par exemple :



    @interface ASingleton : NSObject
    + (instancetype)sharedInstance;
    - (NSUInteger)badMutableState;
    - (void)setBadMutableState:(NSUInteger)badMutableState;
    @end

    @implementation Client1
    - (void)someMethod {
    if ([[ASingleton sharedInstance] badMutableState]) { // ... }
    }
    @end

    @implementation Client2
    - (void)someOtherMethod
    {
    [[ASingleton sharedInstance] setBadMutableState:0];
    }

    @end

    ici les les classes Client1 et Client2 ont une dépendance qui n'est pas explicite, donc si tu mis tous les objets utiles dans ton singleton y aura plein de classes/objets qui vont accéder et en plus d'une manière pas claire, ça risque de créer un code difficile de debuger. 


     


    Moi je me concentrer plus sur le principe de responsabilité de chaque classe et j'essayerai au maximum de ne pas violer ce principe. 


     


    Après bien sur que le singleton est un super pattern mais je pense qu'il faut bien réfléchir avant de l'utiliser. 


     


    Y a une choses aussi que j'ai apprise, qu'il ne faut pas trop chercher la perfection sur le design/architecture de l'application dès le début mais plutôt fais le au fur et à  mesure que tu avances dans le projet.  


     


    Voila c'est mon avis :)

  • Merci Samir pour tes éclaircissements.

    Maintenant il faut savoir que j'aimerai passer 2/3 choses par ce biais pas plus.

    A commencer par le undo manager qui est souvent unique pour une application.

    Et j'ai un cas très particulier ou un contrôle est owné par une vue mais n'est utile que dans une autre... Storyboard oblige. La je suis dans un cas ou le design UI prend le pas sur le design code.


    Cela dit je comprends bien ce que tu veux dire et l'importance d'avoir un code organisé et facile à  maintenir. Mais dans le cas d'un pattern que je défini moi même et auquel je me tiens je vois pas en quoi c'est fondamentalement dérangeant. En plus comme tu le dit un design évolue au fil du développement et il y a des chance que je me rendre compte que ce design n'apporte plus de soucis qu'autre chose ^^
  • FKDEVFKDEV Membre
    juillet 2014 modifié #12

    L'idée d'un objet global n'est pas forcément mauvaise si tu y associes l'idée de fonctionner par protocol.


    Dans ce cas là  cet objet doit avoir la responsabilité de créer les objets qu'il met en relation. Et il doit les mettre en relation par l'intermédiaire de protocol plutôt que par des pointeurs directs.


    La seule responsabilité de cet objet est donc de faire le chef d'orchestre.


    Avant, on pouvait utiliser l'appDelegate pour ça car l'appDelegate ne faisait pas grand chose et il avait déjà  la responsabilité de créer le viewController principal. Ce n'était pas si mauvais que cela jusqu'à  iOS 3.


    Après Apple a donné de plus en plus de responsabilité à  l'appDelegate (multi-tâche, notifications, etc) donc sa responsabilité est devenu l'interaction avec le système plutôt que la gestion des autres objets de l'application.


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