Wie funktioniert ein Unterstrich vor einer Variablen in einer Kakao-Ziel-C-Klasse?


157

Ich habe in einigen iPhone-Beispielen gesehen, dass Attribute einen Unterstrich _ vor der Variablen verwendet haben. Weiß jemand was das bedeutet? Oder wie es funktioniert?

Eine von mir verwendete Schnittstellendatei sieht folgendermaßen aus:

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

@property (nonatomic, retain) UILabel *missionName;

- (Mission *)mission;

Ich bin mir nicht sicher, was genau das oben genannte tut, aber wenn ich versuche, den Missionsnamen wie folgt festzulegen:

aMission.missionName = missionName;

Ich bekomme den Fehler:

Anfrage für das Mitglied 'missionName' in etwas, das keine Struktur oder Gewerkschaft ist

Antworten:


97

Wenn Sie das Unterstrichpräfix für Ihre ivars verwenden (dies ist nichts anderes als eine übliche, aber nützliche Konvention), müssen Sie eine zusätzliche Aktion ausführen, damit der automatisch generierte Accessor (für die Eigenschaft) weiß, welches ivar verwendet werden soll. Insbesondere sollte Ihre Implementierungsdatei folgendermaßen synthesizeaussehen:

@synthesize missionName = _missionName;

Allgemeiner ist dies:

@synthesize propertyName = _ivarName;

78
Bei autosynthetisierenden Eigenschaften ist dies nicht mehr erforderlich. Xcode synthetisiert eine @property xxxx mit einem ivar namens _xxxx hinter den Kulissen. Ordentlich.
LearnCocos2D

@ LearnCocos2D Hallo! Ein Neuling für iOS hier und es gibt etwas, das ich klären muss. Die ganze Zeit , was ich tat , war die erklären , propertyin der h - Datei und in der .m fie ich Zugriff es mit selfwie so self.someProperty. Ist das der richtige Weg? Oder sollte ich die ivars im Code verwenden?
Isuru

Durch das Festlegen des ivar wird der Eigenschaftssetter nicht ausgeführt - Sie entscheiden, ob dies für den jeweiligen Fall eine gute Idee ist oder nicht
LearnCocos2D

Noob Frage: Warum nicht die Ivars direkt verwenden? warum sollte ich eine separate var deklarieren, um den ivar zu halten?
Allen

1
@ Allen, wenn ich Ihre Frage richtig verstehe: Die separate Variable, die Sie deklarieren, ist ein Zeiger auf die tatsächliche Variable. Dies ist aus einigen Gründen wichtig (die ich kenne). Erstens duplizieren Sie den Wert eines Zeigers nicht, wenn Sie ihn an eine Funktion übergeben. Sie teilen der Funktion einfach mit, wo sich der zu verwendende Wert befindet. Dies hilft, Ihren verwendeten Speicher niedrig zu halten (und hilft auch bei der Zuweisung und Freigabe von Speicher, was wichtig ist, wenn in Java keine 'Garbage Collection' vorhanden ist)
David Sigley,

18

Es ist nur eine Konvention für die Lesbarkeit, es tut dem Compiler nichts Besonderes. Sie werden sehen, dass Benutzer es für private Instanzvariablen und Methodennamen verwenden. Apple empfiehlt tatsächlich, den Unterstrich nicht zu verwenden (wenn Sie nicht vorsichtig sind, können Sie etwas in Ihrer Oberklasse überschreiben), aber Sie sollten sich nicht schlecht fühlen, wenn Sie diesen Rat ignorieren. :) :)


19
Soweit ich weiß, empfiehlt Apple, das Unterstrichpräfix für Methodennamen nicht zu verwenden (dies behalten sie sich als Konvention für private Methoden vor), aber sie haben keine solche Empfehlung zu Instanzvariablennamen.
Kelan

9
@Kelan In der Tat, Apple - ermutigt , dies zu tun : „ In der Regel sollten Sie keinen Zugriff Instanzvariablen direkt, stattdessen sollten Sie Zugriffsmethoden verwenden ( was Sie tun Zugang Instanzvariablen direkt in init und dealloc Methoden) helfen , diese zu signalisieren, Präfix - Instanz. Variablennamen mit einem Unterstrich (_), zum Beispiel: \ @implementation MyClass {BOOL _showsTitle;} "
dmirkitanov

Ich glaube nicht, dass Apple uns dazu ermutigt, da alle ihre eigenen Beispielcodes in der iOS-Entwicklerbibliothek nicht das ( ) enthalten. Apple sagt auch, dass sie es reserviert haben, was bedeuten muss, dass sie es intern für ihre eigenen Frameworks wie UIKit usw. verwenden. Deshalb sollten wir es nicht unachtsam verwenden. Aber ich sehe das in dem Link, den Sie @kelan angegeben haben. Sie sagen tatsächlich in der "Revisionshistorie", dass es "geeignet" ist, ( ) zu verwenden. Ich interpretiere es so, wie wir es "benutzen" können, wenn wir wollen.
WYS

Apples Dokumentation , die besagt , nicht den Unterstrich Präfix für Methodennamen zu verwenden , ist hier .
ThomasW

9

Der einzige nützliche Zweck, den ich gesehen habe, ist die Unterscheidung zwischen lokalen Variablen und Mitgliedsvariablen, wie oben angegeben, aber es ist keine notwendige Konvention. In Kombination mit einer @ -Eigenschaft erhöht sich die Ausführlichkeit der Synthetisierungsanweisungen - @synthesize missionName = _missionName;und ist überall hässlich.

Verwenden Sie anstelle des Unterstrichs nur beschreibende Variablennamen in Methoden, die nicht in Konflikt stehen. Wenn sie in Konflikt geraten müssen, sollte der Variablenname innerhalb der Methode einen Unterstrich aufweisen, nicht die Mitgliedsvariable, die von mehreren Methoden verwendet werden kann . Dies ist nur in einem Setter oder in einer Init-Methode üblich. Darüber hinaus wird die Anweisung @synthesize präziser.

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

Bearbeiten: Mit der neuesten Compiler-Funktion der Autosynthese verwende ich jetzt den Unterstrich für den ivar (in seltenen Fällen muss ich einen ivar verwenden, um den Funktionen der Autosynthese zu entsprechen.


Es ist umgekehrt. private Variable ist unterstrichen. das Eigentum nicht. und wenn du sie synthetisierst, koppelst du sie.
Justin

Das ist genau so, wie ich es beschreibe, außer dass ich es eine "Mitgliedsvariable" anstelle einer "privaten Variablen" nannte.
Peter DeWeese

Autsch! Dies ist problematisch. Durch die automatische Synthese wird der ivar _myString erstellt, was bedeutet, dass Ihr Setter nicht funktioniert (da er Ihren ivar dann nicht anhand des Methodenparameters erkennen kann).
Geowar

Richtig, weshalb ich die Bearbeitung am Ende hinzugefügt habe, als Apple die automatische Synthese hinzugefügt hat.
Peter DeWeese

5

Es hat eigentlich nichts zu bedeuten, es ist nur eine Konvention, mit der manche Leute Mitgliedsvariablen von lokalen Variablen unterscheiden.

Der Fehler scheint, als hätte aMission den falschen Typ. Was ist es seine Erklärung?


Es ist in IDEs mit Intellisense üblich; Dadurch werden Ihre Mitglieds- / Modul- / Klassenvariablen oben in der Liste angezeigt. Ein weiteres häufiges Prefix ist "m_"
STW

1
Wenn es nichts bedeutet, wie können Sie dann wie in meinem obigen Beispiel zwischen _missionName und missionName hin und her wechseln? Meine Erklärung sieht folgendermaßen aus: Mission * aMission = [[Mission alloc] init]; aMission.missionName = @ "eine Mission";
Atma

1
Eine ist eine Instanzvariable und die andere ist eine Eigenschaft. Sie können nicht auf Instanzvariablen mit einer Syntax wie aMission.missionName zugreifen, da diese Syntax nicht mit Zeigern funktioniert.
Chuck

Beachten Sie außerdem, dass Sie versuchen, ein Missionsobjekt zu bearbeiten, die von Ihnen mit der Eigenschaft missionName bereitgestellte Schnittstelle jedoch eine MissionCell ist.
Smorgan

2

Dies gilt nur für die Namenskonvention zum Synthetisieren von Eigenschaften.

Wenn Sie Variablen in der .m-Datei synthetisieren, liefert Xcode automatisch _variable Intelligenz.


1

Mit einem Unterstrich können Sie nicht nur Ihre ivars auflösen, ohne auf die self.member- Syntax zurückgreifen zu müssen, sondern Ihren Code auch besser lesbar machen, da Sie wissen, wann eine Variable ein ivar (aufgrund ihres Unterstrichpräfixes) oder ein Elementargument (kein Unterstrich) ist ).

Beispiel:

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

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

In diesem Beispiel wäre es auch schön, einen Vergleich der Verwendung von self.image (oder [self image]) zu sehen. Wann ist es besser, self.image zu verwenden und wann ist es besser, _image zu verwenden?
Boeckm

2
@Boeckm: Im Allgemeinen sollten Sie verwenden self.image, die auf die Eigenschaft zugreift. Das einzige Mal, wenn Sie _imagedirekt auf die Instanzvariable zugreifen sollten , liegt innerhalb von initMethoden und der deallocMethode, wenn das Aufrufen einer anderen Methode riskant sein kann (da das Objekt halb initialisiert oder halb freigegeben ist).
Peter Hosey

1

Dies scheint das "Master" -Element für Fragen zu self.variableName vs. _variablename zu sein. Was mich für eine Schleife warf, war, dass ich in der .h hatte:

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

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

Dies führt dazu, dass self.variableName und _variableName zwei unterschiedliche Variablen in der .m sind. Was ich brauchte war:

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

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

Dann sind in der Klasse '.m self.variableName und _variableName äquivalent.

Was mir immer noch nicht klar ist, ist, warum viele Beispiele immer noch funktionieren, auch wenn dies nicht schwierig ist.

Strahl


0

Anstelle eines Unterstrichs können Sie den Namen self.variable verwenden oder die Variable synthetisieren, um die Variable oder den Ausgang ohne Unterstrich zu verwenden.


2
Wenn Sie nur die Variable in derselben Klasse benötigen, deklarieren Sie sie einfach in der .m-Datei selbst. Dann können Sie ohne Selbst und ohne Unterstrich
aufrufen

0

In den anderen Antworten fehlt, dass die Verwendung _variableverhindert , dass Sie geistesabwesend variableden ivar eingeben und darauf zugreifen, anstatt auf die (vermutlich beabsichtigte) Eigenschaft.

Der Compiler zwingt Sie, entweder self.variableoder zu verwenden _variable. Die Verwendung von Unterstrichen macht die Eingabe unmöglich variable, wodurch Programmiererfehler reduziert werden.

- (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;

}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.