2017-07-15 1 views
1

Ich lerne die Swift Programmiersprache und komme dabei manchmal mit der alten Objective-C Programmiersprache und deren Code in Kontakt.Objective-C: Überschreiben von Getter & Setter mit Instanzvariable (mit _)

Ich bin ein absoluter Anfänger und daher habe ich einige Fragen zum besseren Verständnis der Setter und Getter.

So weiß ich, dass ich eine Instanzvariable durch geschweifte Klammern in der .h-Datei erstellen kann, aber normalerweise verwende ich Eigenschaften. Diese Eigenschaften werden von einer Instanzvariable unterstützt und bieten automatisch eine Getter- und Setter-Methode an.

Beispiel:

Fahrzeug .h-Datei:

@interface Vehicle : NSObject 
@property int myProperty; 
@end 

Weil ich diese Eigenschaft erstellt Ich muss keinen Getter und Setter-Methode in der vehicle.m Datei deklarieren, weil sie automatisch vom Compiler erstellt. So kann ich ein Fahrzeug-Objekt erstellen, setzen und den Wert bekommen.

Beispiel

main.m

Vehicle *myvehicle = [[vehicle alloc] init]; 
[myvehicle myProperty] // myvehicle.myProperty 
[myvehicle setMyProperty : 10] // myvehicle.myProperty = 10; 

Nun las ich, dass es möglich ist, die automatisch erstellt Getter und Setter-Methode meines erstellten Eigenschaft "myProperty" außer Kraft zu setzen. Wenn ich meine eigene Version von Getter und Setter deklariere, muss ich zwei Methoden in der Datei vehicle.h und vehicle.m deklarieren. In der Datei vehicle.m rufe ich das Objekt nicht auf, indem ich das self-Schlüsselwort verwende, sondern indem ich seine automatisch erzeugte Instanzvariable (_myProperty) verwende. Ist es richtig?

Ich habe es versucht, aber immer einen Fehler bekommen und ich weiß nicht warum und was ist der Punkt.

Beispiel

Fahrzeug .h-Datei:

@interface Vehicle : NSObject 
@property int myProperty; 
-(int) myProperty; //my new Getter method 
-(void) setMyProperty: (int)updatedMyProperty; //My new Setter method 
@end 

Fahrzeug .m-Datei:

@implementation Vehicle 

    -(int) myProperty { 
     if (! _myProperty) { 
     _myProperty = NO; 
    } 
     return _myProperty; 
    } 

    -(void) setMyProperty: (int)updatedMyProperty { 
    if (_myProperty == updatedMyProperty) return; 
    _myProperty = updatedMyProperty; 
    } 
    @end 

erhalte ich immer die Fehlermeldung "Die Verwendung von nicht deklarierter Bezeichner" und I don‘ Ich weiß warum. Wenn ich richtig verstanden habe, muss ich den ivar oder seinen Namen nicht mit @synthesize deklarieren, weil der Compiler automatisch den Ivar namens _myProperty für mich erstellt. Ich muss nur @synthesize verwenden, wenn ich den Namen des Ivars ändern möchte.

Ich bin nicht sicher, warum ich stecken bleiben und was der Punkt ist. Kannst du es erklären? Vielen Dank im Voraus!

+0

Unrelated, aber vor Sie haben '[Meinfahrzeug setMyProperty = 10] '. Das sollte klar sein "myvehicle setMyProperty: 10]". – Rob

Antwort

0

Wenn Sie alle Accessor-Methoden implementieren, wird der Compiler nicht mehr automatisch den ivar für Sie synthetisieren. In diesem Fall müssen Sie dies ausdrücklich selbst tun. Z.B.

Dies ist nur notwendig, wenn Sie alle Accessor-Methoden manuell implementiert haben. Der Grund dafür ist, dass der Compiler intelligent genug ist, um zu wissen, dass Sie, wenn Sie die Accessor-Methoden übernehmen, den Ivar nicht brauchen, nämlich dass Sie etwas radikal Anderes tun, z.Berechnen von Werten aus einer anderen Eigenschaft, Festlegen/Abrufen von Werten aus einem anderen Speicher usw. Möglicherweise möchten Sie, dass der Compiler das ivar synthetisiert (in diesem Fall fügen Sie die obige @synthesize-Anweisung hinzu), aber es ist ebenso wahrscheinlich, dass Sie den Accessor implementiert haben Methoden, da kein unterstützender ivar benötigt wird (in diesem Fall würden Sie die obige @synthesize Anweisung weglassen).

Wie auch immer, mit dem einfachen Beispiel zu bleiben, Sie so etwas wie erhalten:

@interface Vehicle : NSObject 
@property (nonatomic) int myProperty; // if you don't write atomic accessor methods, you really should be explicit that this is nonatomic 

// as an aside, even if you implement accessor methods, you don't have to declare them here 
// 
// -(int) myProperty; //my new Getter method 
// -(void) setMyProperty: (int)updatedMyProperty; //My new Setter method 

@end 

Und

@implementation Vehicle 

// since you implemented all of the accessor properties, you have to manually synthesize the ivar 

@synthesize myProperty = _myProperty; 

- (int) myProperty { 
    // do whatever you want here; note, the following doesn't make sense 
    // 
    // if (! _myProperty) { 
    //  _myProperty = NO; 
    // } 

    return _myProperty; 
} 

- (void)setMyProperty:(int)updatedMyProperty { 
    if (_myProperty == updatedMyProperty) return; 
    _myProperty = updatedMyProperty; 
} 
@end 

ist klar, es hat keinen Sinn, diese besonderen Accessormethoden in dem obigen Beispiel in schriftlicher Form, da Sie Ich biete keine neue Funktionalität an, also würdest du nicht. Sie würden nur die selbst synthetisierten Zugriffsmethoden nutzen.

Aber in den Fällen, in denen Sie wirklich Ihre eigenen Accessor-Methoden schreiben müssen, müssen Sie dem Compiler explizit mitteilen, ob Sie ihn benötigen, um den ivar auch für Sie zu synthetisieren oder nicht.

+0

Danke, dass du Rob geholfen hast! Das hat mir wirklich geholfen zu verstehen, warum und was hinter den Kulissen passiert. Dass ich meinen Ivar manuell synthetisieren muss, wenn ich Getter und Setter außer Kraft setze, wurde in dem Buch, das ich verwende, nicht deklariert. Also, zusammenfassend: In den meisten Fällen muss ich nichts synthetisieren. Wenn ich einen, Getter oder Setter überschreiben möchte, weil ich mehr Code implementieren möchte, muss ich nichts tun, nur um zu überschreiben. Wenn ich beide überschreiben möchte, muss ich den ivar manuell synthetisieren, aber wie gesagt, in den meisten Fällen ist es nicht notwendig, dies zu tun. Danke noch einmal! – Ari

-1

Wenn Sie das nichtatomare Attribut verwenden, können Sie entweder Getter oder Setter oder beides überschreiben. Der Compiler kümmert sich um den Rest.

@property (nonatomic) int yourInt; 

dann schreiben Getter oder Setter in .m-Datei

-(int)yourInt 
{ 
// do something 
return _yourInt; 
} 

-(void)setYourInt:(int)someInt 
{ 
// do something 
_yourInt = someInt; 
} 

eine Notiz zum Unterschied von diesen:

_yourInt; //access variable directly 
[self yourInt]; // use getter method 

_yourInt = 4; // set vsriable directly 
[self setYourInt:4]; // use setter method 
+0

Ich habe nicht abgestimmt, aber zwei Dinge: Erstens sollte die 'getYourInt' Methode' yourInt' sein. Objective-C verwendet für Getter nicht das Präfix "get", wie Sie es in anderen Sprachen sehen. Tatsächlich ist dieser Tippfehler der einzige Grund, warum Ihr Beispiel funktioniert, weil Sie nicht alle Accessor-Methoden implementiert haben und Xcode nur die IVAR-Synthese umgeht, wenn Sie alle Accessor-Methoden implementiert haben. Zweitens ist die Angabe von "atomar" nicht relevant. (In der Tat, wenn Sie den Atomizitätsqualifikator weglassen, wird "atomar" angenommen.) – Rob

+0

danke für Klarstellung! –

+0

Gut. Aber das Problem ist jetzt, dass Sie 'yourInt' und' setYourInt' korrekt implementiert haben, das ivar, '_yourInt', wird nicht mehr automatisch für Sie synthetisiert. Tatsächlich ist dies die OP-Frage, nämlich warum sie nicht automatisch synthetisiert wird. – Rob