web-dev-qa-db-fra.com

Comment un trait de soulignement devant une variable dans une classe cacao objective-c fonctionne-t-il?

J'ai vu dans quelques exemples d'iPhone que les attributs ont utilisé un trait de soulignement _ devant la variable. Est-ce que quelqu'un sait ce que cela signifie? Ou comment ça marche?

Un fichier d'interface que j'utilise ressemble à:

@interface MissionCell : UITableViewCell {
    Mission *_mission;
    UILabel *_missionName;
}

@property (nonatomic, retain) UILabel *missionName;

- (Mission *)mission;

Je ne sais pas exactement ce que cela fait, mais lorsque j'essaie de définir le nom de la mission comme suit:

aMission.missionName = missionName;

Je reçois l'erreur:

demande de membre 'missionName' dans quelque chose qui n'est pas une structure ou une union

156
Atma

Si vous utilisez le préfixe de soulignement pour vos ivars (qui n'est rien de plus qu'une convention commune, mais utile), vous devez alors effectuer une opération supplémentaire afin que l'accesseur généré automatiquement (pour la propriété) sache quel ivar utiliser. Plus précisément, dans votre fichier d'implémentation, votre synthesize devrait ressembler à ceci:

@synthesize missionName = _missionName;

Plus généralement, c'est:

@synthesize propertyName = _ivarName;
96
Kelan

C'est juste une convention de lisibilité, cela ne fait rien de spécial au compilateur. Vous verrez que les gens l'utilisent pour des variables d'instance privées et des noms de méthodes. Apple recommande en fait de ne pas utiliser le trait de soulignement (si vous ne faites pas attention, vous pouvez remplacer quelque chose de votre superclasse), mais vous ne devriez pas vous sentir mal à l'idée de ne pas tenir compte de ce conseil. :)

18

Le seul objectif utile que j’ai vu est de différencier les variables locales des variables membres, comme indiqué ci-dessus, mais ce n’est pas une convention nécessaire. Lorsqu'il est associé à une propriété @, il augmente la verbosité des instructions de synthèse - @synthesize missionName = _missionName;, et est moche partout.

Au lieu d'utiliser le trait de soulignement, utilisez simplement des noms de variables descriptifs dans les méthodes qui ne sont pas en conflit. Quand ils doivent entrer en conflit, le nom de la variable dans la méthode doit avoir un caractère de soulignement, pas la variable membre qui peut être utilisée par plusieurs méthodes. Le seul endroit commun où cela est utile est dans un setter ou dans une méthode init. De plus, la déclaration @synthesize sera plus concise.

-(void)setMyString:(NSString*)_myString
{
    myString = _myString;
}

Edit: Avec la dernière fonctionnalité de synthèse automatique du compilateur, j’utilise maintenant le trait de soulignement pour ivar (dans les rares cas où j’ai besoin d’utiliser un ivar pour correspondre à ce que fait la synthèse automatique.

9
Peter DeWeese

Cela ne veut vraiment rien dire, c'est simplement une convention que certaines personnes utilisent pour différencier les variables membres des variables locales.

En ce qui concerne l'erreur, il semble que le type d'une mission soit incorrect. Qu'est-ce que sa déclaration?

5
smorgan

Ceci est uniquement pour la convention de nommage des propriétés de synthèse.

Lorsque vous synthétisez des variables dans le fichier .m, Xcode vous fournira automatiquement l'intelligence _variable.

2
Dipak Narigara

Avoir un trait de soulignement permet non seulement de résoudre vos ivars sans recourir à la syntaxe self.member, mais rend votre code plus lisible puisque vous savez quand une variable est un ivar (à cause de son préfixe de soulignement) ou un argument membre (sans trait de soulignement).

Exemple:

- (void) displayImage: (UIImage *) image {

    if (image != nil) {
        // Display the passed image...
        [_imageView setImage: image];
    } else {
        // fall back on the default image...
        [_imageView setImage: _image];
    }
}
1
Jason Fuerstenberg

Cela semble être l'élément "maître" pour les questions sur self.variableName et _variablename. Ce qui me jeta un tour, c’est que dans le .h, j’avais:

...
@interface myClass : parentClass {
className *variableName;    // Note lack of _
}

@property (strong, nonatomic) className  *variableName;
...

Cela conduit à self.variableName et _variableName étant deux variables distinctes dans le fichier .m. Ce dont j'avais besoin était:

...
@interface myClass : parentClass {
className *_variableName;    // Note presence of _
}

@property (strong, nonatomic) className  *variableName;
...

Ensuite, dans la classe '.m, self.variableName et _variableName sont équivalents.

Ce que je ne comprends toujours pas, c'est pourquoi de nombreux exemples fonctionnent toujours, même si cela n’est pas fait.

Rayon

1
RayInNoIL

Il manque dans les autres réponses que l'utilisation de _variable vous empêche de taper distraitement variable et d’accéder à ivar plutôt qu’à la propriété (supposée voulue).

Le compilateur vous obligera à utiliser soit self.variable ou _variable. L'utilisation de traits de soulignement rend impossible la saisie de variable, ce qui réduit les erreurs de programmation.

- (void)fooMethod {

    // ERROR - "Use of undeclared identifier 'foo', did you mean '_foo'?"
    foo = @1;

    // So instead you must specifically choose to use the property or the ivar:

    // Property
    self.foo = @1;

    // Ivar
    _foo = @1;

}
0
pkamb

au lieu du trait de soulignement, vous pouvez utiliser le nom self.variable ou synthétiser la variable pour utiliser la variable ou la sortie sans trait de soulignement.

0
SARATH SASI