web-dev-qa-db-fra.com

Instanciation paresseuse dans le développement Objective-C/iPhone

Question rapide ... Eh bien, je comprends que toutes les propriétés commencent nuls dans Objective-C et que l'envoi d'un message à nil ne fait rien; vous devez donc initialiser à l'aide de [[Class alloc] init]; avant d'envoyer un message à une propriété nouvellement créée. Cependant, qu'en est-il si je n'envoie pas de messages à cette propriété ou si je la définit à l'aide de self.property = quelque chose? Dois-je également affecter init dans ces cas? De plus, les propriétés de l'interface utilisateur sont-elles au départ nuls également, par exemple une propriété UILabel que vous faites glisser à partir de votre storyboard? Est-ce que ceux-ci doivent alloc init?

Merci à tous ceux qui répondent 

24
user1452574

Stunner a bien expliqué qu'il n'était pas nécessaire d'allouer des objets init déjà créés.

Mais si c'est un objet qui n'existe pas, où allez-vous le créer? Un schéma très courant, que je mentionne parce que vous l'avez mentionné dans votre message, est l'instanciation paresseuse.

Donc, vous voulez une propriété NSMutableArray. Vous pouvez allouer init avec une méthode avant de l'utiliser, mais vous devez ensuite vous soucier de "cette méthode est-elle appelée avant d'avoir besoin de mon tableau?" ou "est-ce que je vais l'appeler accidentellement et le réinitialiser."

Donc, un endroit sûr pour le faire est dans le getter de la propriété. Il est appelé à chaque fois que vous accédez à la propriété. 

.h
@property (nonatomic, strong) NSMutableArray* myArray;

.m
@synthesize myArray = _myArray;

- (NSMutableArray*)myArray
{
    if (!_myArray) {
        _myArray = [[NSMutableArray alloc] initWithCapacity:2];
    }
    return _myArray;
}

Chaque fois que vous accédez à cette propriété, le message "myArray existe-t-il? Sinon, créez-le. Si tel est le cas, renvoyez ce que j'ai."

De plus, ce modèle de conception présente l'avantage supplémentaire de ne pas créer de ressources tant que vous n'en avez pas besoin, mais de les créer toutes en même temps, par exemple, lors du chargement de votre contrôleur de vue ou du lancement de votre application, ce qui, selon les besoins, peut prendre plusieurs secondes.

39
Jason C. Howlin

En réalité, lorsque vous faites self.myProperty = [[Class alloc] init], vous n’initialisez pas votre propriété. Vous initialisez plutôt un objet que vous indiquez à votre propriété (qui est en fait un pointeur). Donc, si vous avez déjà un objet alloué et initialisé, vous n'avez plus besoin d'allouer/init et vous pouvez faire self.myProperty = object;

Les propriétés de l'interface utilisateur ne démarrent pas comme nil, car lorsque vous ajoutez des éléments dans le générateur d'interface, la vue est propriétaire des éléments que vous ajoutez et ces objets sont automatiquement initialisés. Cela signifie que si vous créez des IBOutlets et les connectez à certaines propriétés, vous n'avez pas besoin d'allouer/init.

J'espère que cela a été utile.

3
Kaan Dedeoglu

Je n'ai pas d'expérience avec Storyboards, mais je sais que lorsque vous créez des objets via un fichier xib, tous les objets sont correctement instanciés lorsque vous indiquez à un contrôleur de vue d'utiliser un fichier xib. Vous n'avez donc pas à vous soucier d'allouer/initialiser ces objets dans le code.

En ce qui concerne l'utilisation de self.property = <something>, cela dépend de ce que something est. Si quelque chose est un objet existant, vous n'avez pas besoin de faire l'allocation-init sur cet objet car la syntaxe self.property = ... appelle la méthode setter de la propriété qui conservera, copiera, affectera, etc.

Désormais, toute sorte d'objet existant peut être un objet alloc/init'ed ou un objet autoreleased obtenu à l'aide d'une méthode pratique (stringWithFormat de NSString, par exemple).

Comme Kaan Dedeoglu l'a fait remarquer, la syntaxe self.property = ... pointe (et conserve) l'ivar vers l'objet en mémoire, et il vous incombe d'initialiser cet objet s'il n'est pas déjà instancié.

1
Stunner

Non, vous n'avez pas besoin de [[Class alloc]] initialiser les propriétés dans votre méthode init. 

Cependant, je vous encourage à les définir explicitement sur Nil dans votre méthode init pour plus de clarté.

0
grillp