Warum sollen synthetisierte Eigenschaften in iOS mit führenden Unterstrichen umbenannt werden?

Mögliche Duplikate:
Wie funktioniert ein Unterstrich vor einer Variablen in einer cocoa-Ziel-C-class?

Wenn Sie in Xcode 4 ein neues Projekt erstellen, fügt der Standardcode ein Unterstrich hinzu, wenn die Ivars in der Implementierungsdatei folgendermaßen synthetisiert werden:

@synthesize window = _window; 

oder:

 @synthesize managedObjectContext = __managedObjectContext; 

Kann mir jemand sagen, was hier geleistet wird? Ich bin kein kompletter Nub, aber das ist ein Aspekt von Ziel-C, den ich nicht verstehe.

Ein weiterer Punkt der Verwirrung; In der App-Delegate-Implementierung wird nach dem Synthetisieren des Fensters iVar wie oben in der Anwendung didFinishLaunchingWithOptions: method auf die iVars window und viewController mit self verwiesen:

 self.window.rootViewController = self.viewController [self.window makeKeyAndVisible]; 

aber in der Dealloc-Methode ist _window oder _viewController

Vielen Dank

Solutions Collecting From Web of "Warum sollen synthetisierte Eigenschaften in iOS mit führenden Unterstrichen umbenannt werden?"

Dies ist ein Artefakt einer früheren Version der Objective-C-Laufzeit.

Ursprünglich wurde @synthesize verwendet, um @synthesize zu erstellen, aber die Laufzeitumgebung benötigte weiterhin, dass Instanzvariablen explizit instanziiert werden mussten:

 @interface Foo : Bar { Baz *_qux; } @property (retain) Baz *qux; @end @implementation Foo @synthesize qux = _qux; - (void)dealloc { [_qux release]; [super dealloc]; } @end 

Personen würden ihren Instanzvariablen Präfix voranstellen, um sie von ihren Eigenschaften zu unterscheiden (obwohl Apple nicht möchte, dass Sie Unterstriche verwenden, aber das ist eine andere Sache). Sie synthetisieren die Eigenschaft so, dass sie auf die Instanzvariable zeigt. Aber der Punkt ist, _qux ist eine Instanzvariable und self.qux (oder [self qux] ) ist die Nachricht, die an das Objekt self gesendet wird.

Wir verwenden die Instanzvariable direkt in -dealloc ; stattdessen würde die Accessor-Methode so aussehen (obwohl ich es aus Gründen, die ich in Kürze erklären werde, nicht weiterempfehle):

 - (void)dealloc { self.qux = nil; // [self setQux:nil]; [super dealloc]; } 

Dies hat den Effekt, dass qux wird und die Referenz auf qux wird. Aber das kann unglückliche Nebenwirkungen haben:

  • Sie können am Ende einige unerwartete Benachrichtigungen auslösen. Andere Objekte können Änderungen an qux , die aufgezeichnet werden, wenn eine qux verwendet wird, um sie zu ändern.
  • (In diesem Punkt stimmen nicht alle überein 🙂 Wenn Sie den pointers als Accessor auf Null setzen, werden möglicherweise Logikerrors in Ihrem Programm ausgeblendet. Wenn Sie jemals auf eine Instanzvariable eines Objekts zugreifen, nachdem das Objekt freigegeben wurde, tun Sie etwas ernsthaft falsch. Aufgrund der Semantik von Objective-C ohne Nullen werden Sie jedoch nie wissen, dass Sie den Accessor auf nil . Hätten Sie die Instanzvariable direkt freigegeben und die Referenz nicht auf Null gesetzt, hätte ein Zugriff auf das freizugebende Objekt eine laute EXC_BAD_ACCESS .

Spätere Versionen der Laufzeitumgebung haben die Möglichkeit hinzugefügt, Instanzvariablen zusätzlich zu den Accessor-Methoden zu synthetisieren. Mit diesen Versionen der Laufzeit kann der obige Code unter Weglassung der Instanzvariablen geschrieben werden:

 @interface Foo : Bar @property (retain) Baz *qux; @end @implementation Foo @synthesize qux = _qux; - (void)dealloc { [_qux release]; [super dealloc]; } @end 

Dies erzeugt tatsächlich eine Instanzvariable auf Foo namens _qux , auf die die Getter- und Setter-Nachrichten -qux und -setQux: .

Ich empfehle dagegen: Es ist ein wenig unordentlich, aber es gibt einen guten Grund, den Unterstrich zu verwenden; nämlich zum Schutz gegen versehentlich direkten Zugriff auf den Ivar. Wenn Sie der Meinung sind, dass Sie sich selbst vertrauen können, dass Sie eine rohe Instanzvariable oder eine Accessor-Methode verwenden, tun Sie es stattdessen wie folgt:

 @interface Foo : Bar @property (retain) Baz *qux; @end @implementation Foo @synthesize qux; - (void)dealloc { [qux release]; [super dealloc]; } @end 

Wenn Sie dann direkt auf die Instanzvariable zugreifen möchten, sagen qux einfach qux (was in self->qux in C-Syntax für den Zugriff auf ein Member aus einem pointers übersetzt). Wenn Sie self.qux verwenden self.qux (die Beobachter benachrichtigen und andere interessante Dinge tun und die Dinge hinsichtlich der Speicherverwaltung sicherer und einfacher machen), verwenden Sie self.qux ( [self qux] ) und self.qux = blah; ( [self setQux:blah] ).

Die traurige Sache hier ist, dass Apples Beispielcode und Vorlagencode saugt. Verwenden Sie es nie als Anleitung für den richtigen Objective-C-Stil und verwenden Sie es keinesfalls als Leitfaden für die richtige Softwarearchitektur. 🙂

Hier ist ein anderer Grund. Ohne Unterstreichung von Instanzvariablen erhalten Sie häufig eine Warnung mit den Parametern self.title = title und self.rating = rating :

 @implementation ScaryBugData @synthesize title; @synthesize rating; - (id)initWithTitle:(NSString *)title rating:(float)rating { if (self = [super init]) { self.title = title; // Warning. Local declaration hides instance variable self.rating = rating; // Warning. Local declaration hides instance variable } return self; } @end 

Sie vermeiden Warnungen durch Unterstreichen von Instanzvariablen:

 @implementation ScaryBugData @synthesize title = _title; @synthesize rating = _rating; - (id)initWithTitle:(NSString *)title rating:(float)rating { if (self = [super init]) { self.title = title; // No warning self.rating = rating; // No warning } return self; } @end 

In der Anwendung didFinishLaunchingWithOptions: method wird auf die iVars von window und viewController mit self verwiesen

Nein, sind sie nicht. viewController sind Verweise auf das Eigenschaftenfenster und viewController . Das ist der Sinn des Unterstrichs, um es klarer zu machen, wenn die Eigenschaft verwendet wird (kein Unterstrich) und wenn direkt auf den ivar zugegriffen wird (mit Unterstrich).

Ja, es ist nur die Referenz des Objekts zu unterscheiden. Das heißt, wenn das Objekt direkt bezeichnet wird, verwenden Sie es mit Unterstreichung, andernfalls verwenden Sie self, um das Objekt zu verweisen.