Benötigen deklarierte Eigenschaften eine entsprechende Instanzvariable?

101

Erfordern Eigenschaften in Objective-C 2.0 die Deklaration einer entsprechenden Instanzvariablen? Zum Beispiel bin ich es gewohnt, so etwas zu tun:

MyObject.h

@interface MyObject : NSObject {
NSString *name;
}
@property (nonatomic, retain) NSString *name;
@end

MyObject.m

@implementation
@synthesize name;
@end

Was wäre, wenn ich dies stattdessen tun würde:

MyObject.h

@interface MyObject : NSObject {
}
@property (nonatomic, retain) NSString *name;
@end

Ist das noch gültig? Und unterscheidet es sich in irgendeiner Weise von meinem vorherigen Beispiel?

Indragie
quelle
Warum ist das zweite fett gedruckte 'MyObject.h' nicht 'MyObject.m'?
Ríomhaire

Antworten:

93

Wenn Sie die Modern Objective-C-Laufzeit verwenden (entweder iOS 3.x oder höher oder 64-Bit-Schneeleopard oder höher), müssen Sie in solchen Fällen keine Ivars für Ihre Eigenschaften definieren.

Wenn Sie @synthesizedas Eigentum haben, wird der Ivar tatsächlich auch für Sie synthetisiert. Dies umgeht das "fragile-ivar" -Szenario. Sie können mehr darüber auf Cocoa with Love lesen

jbrennan
quelle
71

In Ihrer Benutzeroberfläche können Sie eine Instanzvariable zwischen den geschweiften Klammern oder über @propertyaußerhalb der geschweiften Klammern oder über beide formell deklarieren . In jedem Fall werden sie zu Attributen der Klasse. Der Unterschied besteht darin, dass Sie, wenn Sie deklarieren @property, implementieren können, indem Sie @synthesizeIhren Getter / Setter automatisch für Sie codieren. Der Auto-Coder-Setter initialisiert beispielsweise Ganzzahlen und schwebt auf Null. Wenn Sie eine Instanzvariable deklarieren und KEINE entsprechende angeben @property, können Sie keinen eigenen Getter / Setter verwenden @synthesizeund müssen diesen schreiben.

Sie können den automatisch codierten Getter / Setter jederzeit überschreiben, indem Sie Ihren eigenen angeben. Dies geschieht üblicherweise mit der managedObjectContextEigenschaft, die träge geladen wird. Sie deklarieren also Ihre managedObjectContextals Eigenschaft, schreiben dann aber auch eine -(NSManagedObjectContext *)managedObjectContextMethode. Denken Sie daran, dass eine Methode, die denselben Namen wie eine Instanzvariable / -eigenschaft hat, die Methode "getter" ist.

Die @propertyDeklarationsmethode ermöglicht Ihnen auch andere Optionen wie retainund readonly, die die Deklarationsmethode für Instanzvariablen nicht bietet. Grundsätzlich ivarist der alte Weg, und @propertyerweitert ihn und macht es schicker / einfacher. Sie können sich entweder auf das Selbst beziehen. Präfix oder nicht, es spielt keine Rolle, solange der Name für diese Klasse eindeutig ist. Wenn Ihre Oberklasse den gleichen Namen einer Eigenschaft wie Sie hat, müssen Sie entweder self.name oder super.name angeben, um anzugeben, über welchen Namen Sie sprechen.

Auf diese Weise werden immer weniger Personen ivars zwischen den geschweiften Klammern deklarieren und stattdessen nur noch angeben @propertyund dann tun @synthesize. Sie können @synthesizein Ihrer Implementierung nicht ohne eine entsprechende tun @property. Der Synthesizer weiß nur aus der @propertySpezifikation, um welche Art von Attribut es sich handelt . Mit der Synthesize-Anweisung können Sie auch Eigenschaften umbenennen, sodass Sie innerhalb Ihres Codes auf eine Eigenschaft mit einem Namen (Kurzform) verweisen können, außerhalb der .h-Datei jedoch den vollständigen Namen verwenden. Mit der wirklich coolen Autovervollständigung, die XCode jetzt hat, ist dies jedoch weniger vorteilhaft, aber immer noch vorhanden.

Ich hoffe, dies hilft, all die Verwirrung und Fehlinformationen zu beseitigen, die da draußen herumschwirren.

Papa Schlumpf
quelle
Heute ist es nicht mehr obligatorisch, @synthesize zu schreiben. Wie ist diese Antwort in diesem Fall gültig?
Raaz
Sie MÜSSEN <code> @property ... @ synthetize </ code> nicht deklarieren. Durch die Verwendung von Synthetisieren müssen Sie keinen Getter / Setter in Ihre Implementierung schreiben. Wenn Sie nicht synthetisieren, müssen Sie Ihren eigenen Getter / Setter
rollen
2
@PapaSmurf Das ist falsch. Sie können sie selbst verwenden @propertyund nicht verwenden @synthesizeund nicht implementieren. Der Compiler wird automatisch synthesizefür Sie arbeiten, ohne dass Sie dies mehr schreiben müssen.
Jbrennan
8

Es funktioniert in beide Richtungen, aber wenn Sie sie nicht in geschweiften Klammern deklarieren, werden ihre Werte im Debugger in xcode nicht angezeigt.

Rickm
quelle
3

Aus der Dokumentation:

Im Allgemeinen ist das Verhalten von Eigenschaften sowohl für moderne als auch für ältere Laufzeiten identisch (siehe „Laufzeitversionen und -plattformen“ im Objective-C-Laufzeitprogrammierungshandbuch). Es gibt einen wesentlichen Unterschied: Die moderne Laufzeit unterstützt die Synthese von Instanzvariablen, die ältere Laufzeit hingegen nicht.

Damit @synthesize in der alten Laufzeit funktioniert, müssen Sie entweder eine Instanzvariable mit demselben Namen und kompatiblen Typ der Eigenschaft angeben oder eine andere vorhandene Instanzvariable in der Anweisung @synthesize angeben. Wenn Sie in der modernen Laufzeit keine Instanzvariable angeben, fügt der Compiler eine für Sie hinzu.

Charlie Elliott
quelle
3

Wenn Sie XCode 4.4 oder höher verwenden, wird ein Synthesecode für Instanzvariablen für Sie generiert.

Sie müssen nur Eigenschaften wie unten deklarieren; Es generiert Synthesecode und Instanzvariablen, die Code für Sie deklarieren.

@property (nonatomic, strong) NSString *name;

Es wird synthetisierender Code als generiert

@synthesize name = _name;

und Sie können auf die Instanzvariable mit _name zugreifen, ähnlich wie beim Deklarieren

NSString* _name

aber wenn Sie schreibgeschützte Eigenschaft deklarieren, gefällt es

@property (nonatomic, strong, readonly) NSString *name;

Es wird Code generiert

@synthesize name;

oder

@synthesize name = name; 

Sie sollten also auf den Namen der Sofortvariablen ohne Präfix "_" zugreifen, wenn Sie Ihren eigenen Synthesecode schreiben möchten. Der Compiler generiert dann Code für Sie. Du kannst schreiben

@synthesize name = _name;
Shafraz Buhary
quelle
1

Die Programmiersprache Objective-C: Richtlinien zur Implementierung von Eigenschaften

Es gibt Unterschiede im Verhalten der Accessorsynthese, die von der Laufzeit abhängen (siehe auch „Laufzeitunterschied“):

  • Für die Legacy-Laufzeiten müssen Instanzvariablen bereits im @ interface-Block der aktuellen Klasse deklariert sein. Wenn eine Instanzvariable mit demselben Namen wie die Eigenschaft vorhanden ist und ihr Typ mit dem Typ der Eigenschaft kompatibel ist, wird sie verwendet. Andernfalls wird ein Compilerfehler angezeigt.

  • Für die modernen Laufzeiten (siehe „Laufzeitversionen und -plattformen“ im Objective-C-Laufzeitprogrammierhandbuch) werden Instanzvariablen nach Bedarf synthetisiert. Wenn bereits eine gleichnamige Instanzvariable vorhanden ist, wird diese verwendet.

Nate
quelle