Lazy instanciation vs. global instanciation

Bonjour,


 


Dans le CS193P de Standford, le prof fait toujours de la lazy instanciation.


Il dit que comme ça il est sûr de ne pas avoir nil comme retour.


 


Certes, mais du coup, à  chaque fois qu'il appelle son getter, il a un test en plus à  faire.


 


Ne serait-il pas plus logique d'instancier les @properties dans la méthode init ?


 


 


 


Et vous, que faites-vous ?


Réponses

  • pour moi un lazzy instanciation : il me semble qu'un test sur nil ne coûte pas trop cher...


  • Idem... lazy instanciation.


  • AliGatorAliGator Membre, Modérateur

    Je n'en fais pas souvent de la lazy instanciation (je m'embête pas à  réimplémenter tous mes getters), je n'en fais que quand j'estime que c'est vraiment nécessaire et que ça a un gain.


    Et dans ce cas je fais plutôt un dispatch_once.


  • @Ali : donc, tu initialises tes properties dans init généralement ? 


  • samirsamir Membre
    septembre 2013 modifié #6

    Salut,


     


    ça dépend comment tu construis tes inits de tes objets. Tout objet qui déclare des variables d'instances doit avoir une méthode initialisation avec des paramètres initiales sauf si les valeurs par defaut suffisent pour construire l'objet d'une manière utilisable.


     


    Si les valeurs par défaut ne suffisent pas, donc il te faut un custom init et c'est la que tu doit initialiser tes variables d'instances.


     


    par exemple dans cet exemple, MyObject doit avoir au moins un Id pour fonctionner, dans ce cas tu doit l'initialiser dans ton init spécial, et l'object name tu peux le laisser a sa valeur par défaut (nil).



    @interface MyObject : NSObject

    @property (nonatomic, strong) NSString *objectId;
    @property (nonatomic, strong) NSStrig *objectName;

    - (id)initWithId:(NSString *)myId;

    @end

    @implementation MyObject : NSObject

    - (id)initWithId:(NSString *)myId{
    self = [super init];
    if (self){
    _objectId = myId;
    }
    return self;
    }
    @end

    2. Je fait de lazy instanciation quand je suis obligé de redéfinir mon getter, sinon je laisse comme ça.


  • AliGatorAliGator Membre, Modérateur
    Pardon, je n'ai pas regardé la session de Stanford en question, et c'est vrai qu'il y a plusieurs type de lazy loarding :
    - Avoir une méthode qui te dit quand ton objet (ViewController par exemple) va être utilisé, en particulier sa vue chargée (viewDidLoad), qui se différencie de l'init qui est quand le VC est instancié. Dans ce cas on peut considérer que mettre son code d'initialisation dans viewDidLoad est du lazy-loading, un peu
    - Implémenter les Getters pour qu'il créent l'objet que tu veux que la première fois que tu le demandes, et pas avant, par exemple:
    -(NSArray*)categories
    {
    static NSArray* events = nil;
    static dispatch_once_t once;
    dispatch_once(once, ^{
    // Uniquement la première fois qu'on demande les catégories, aller les chercher
    // dans le fichier PLIST où je les stoque. Et les garder ensuite en mémoire pour
    // ne pas aller les recharger du fichier les fois suivantes
    NSString* categoriesFile = [[NSBundle mainBundle] pathForResource:@categories ofType:@plist];
    events = [NSArray arrayWithContentsOfFile:categoriesFile];
    });
    return events;
    }
    Là  je fais bien du Lazy-Loading car je ne vais lire mon fichier categories.plist, pour charger les catégories depuis ce fichier, qu'une seule fois, mais surtout pas avant d'en avoir besoin. Je ne charges pas ce plist dans le init de mon objet, je le charge au premier appel de ma méthode, donc pas avant que qqun me demande ce tableau de catégories.
    Et le dispatch_once me permet de ne pas rappeler cette méthode lors des appels suivants (ce qui est mieux que de tester si events est nil ou pas car si jamais il y a un problème avec le fichier categories.plist genre il est introuvable, events vaudra bien nil même après avoir tenté de charger le PLIST)

    C'est ça que j'appelle du lazy-loading ou de la lazy-instanciation. Et dans l'exemple que j'ai donné ça a du sens car de toute façon je dois lire un PLIST pour charger mes catégories, opération qui peut prendre un peu de temps, autant ne le faire que quand c'est demandé et ne pas s'embêter avec si personne ne les demande jamais.
  • samirsamir Membre
    septembre 2013 modifié #8



    -(NSArray*)categories
    {
    static NSArray* events = nil;
    static dispatch_once_t once;
    dispatch_once(once, ^{
    // Uniquement la première fois qu'on demande les catégories, aller les chercher
    // dans le fichier PLIST où je les stoque. Et les garder ensuite en mémoire pour
    // ne pas aller les recharger du fichier les fois suivantes
    NSString* categoriesFile = [[NSBundle mainBundle] pathForResource:@categories ofType:@plist];
    events = [NSArray arrayWithContentsOfFile:categoriesFile];
    });
    return events;
    }



     


    Je l'aurais déclarée en méthode de classe, puisque c'est la même valeur pour toutes les instances, alors ça sert a rien que toutes les instances sachent répondre "categories" . non ?


  • AliGatorAliGator Membre, Modérateur
    Oui tout à  fait a vrai dire j'ai inventé l'exemple en le tapant sans trop réfléchir + que ça au contexte mais oui ^^
  • Par habitude, j'initialise dans l'init.


    Quand on doit gérer la mémoire, c'est plus facile de travailler de manière symétrique. Par exemple :

    Instantiation dans init.

    Libération dans dealloc.

    Surtout avec des langages comme le C, où on doit de toute manière faire une init de la variable à  zéro manuellement.


    Le lazy loading a des vertus pedagogiques car si on suit l'execution pas à  pas a partir de n'importe quel endroit, on voit comment sont (ou ont été) initialisés les objets qu'on utilise, cela evite de retourner voir l'init à  chaque fois.


    Le lazy loading est moins deterministe qu'une instanciation dans l'init. C'està  dire qu'on maitrise l'ordre des inits et qu'une fois l'init passé, on est sur de ne pas avoir de suprise.
Connectez-vous ou Inscrivez-vous pour répondre.