2012-03-24 8 views
2

Ich habe eine allgemeine Frage über Eigenschaften und Ivars.Konzepte von Eigenschaften mit entsprechenden Ivars

Ich habe viele verschiedene Beispiele gesehen, um Eigenschaften zu benutzen, und es verwirrt mich ein bisschen.

Methode 1 nur mit einer Eigenschaft ohne eine entsprechende ivar.

@property (...) Type *name; 

@synthesize name; 

Methode 2 eine Eigenschaft und ein Ivar mit

@interface{ 
Type *ivarName; 
} 
@property (...) Type *name; 

@synthesize name = ivarName; 

Methode 3 ignorieren Eigenschaften und das Arbeiten mit ivars

@interface{ 
Type *ivarName; 
} 
ivar = ...; 

i 1 i für die meisten Dinge verwenden Methode, die derzeit mach es einfach. aber ich habe mich gefragt, ob ich hier etwas verpassen könnte. Ich habe eine Menge Fragen über VS-Eigenschaften von iVars gelesen, aber keiner von ihnen schien sich wirklich darum zu kümmern, wie sie zusammenarbeiten.

In den meisten Beispielprojekten habe ich Methode 2 verwendet. Also meine Frage ist: Gibt es einen Vorteil bei der Definition einer Eigenschaft und eines ivar, und dann die Eigenschaft dem ivar zuweisen, als nur eine Eigenschaft?

ist die Lösung so einfach wie: nur mit einer Eigenschaft kann ein ivar von 'außerhalb' gesetzt werden?

Ich habe gelesen: Must every ivar be a property? und Property vs. ivar in times of ARC aber war nicht in der Lage, eine endgültige Schlussfolgerung zu ziehen.

Antwort

2

is the solution as simple as: only with a property can an ivar be set from 'outside'?

Im Wesentlichen ja. Ivars in Obj-C sind (standardmäßig) "geschützt", was bedeutet, dass der Compiler es nicht erlaubt, auf sie extern auf den eigenen Code des Objekts zuzugreifen. Zum Beispiel der folgende Klassendeklaration gegeben:

@interface Dunstable : NSObject 
{ 
    NSString * crunk; 
} 
@end 

Man könnte denken, Sie in der Lage sein würden, die Ivar nach dem Erstellen auf das Objekt zuzugreifen, sondern versuchen, zu einem Fehler:

Dunstable * d = [[Dunstable alloc] init]; 
d->crunk = @"Forsooth"; // Error: "Instance variable 'crunk' is protected 

, deshalb, ObjC verwendet Accessor-Methoden. Definieren sie manuell vor dem Aufkommen der deklarierten Eigenschaften obligatorisch wurde:

@implementation Dunstable 

- (NSString *)crunk { 
    return crunk; // implicit ivar access, i.e. self->crunk 
} 

- (void)setCrunk: (NSString *)newCrunk { 
    [newCrunk retain]; 
    [crunk release]; 
    crunk = newCrunk; 
} 

@end 

nun mit den @property und @synthesize Richtlinien schafft diese Zugriffsmethoden für Sie (wie auch die Variable selbst). (Die manuelle Speicherverwaltung in dem Setter ist natürlich unter ARC auch veraltet.)

Es ist möglich, eine Ivar zu machen, die von außerhalb des Objekt zugänglich ist:

@interface Dunstable : NSObject 
{ 
    @public 
    NSNumber * nonce; 
} 
@end 

Dunstable * d = [[Dunstable alloc] init]; 
d->nonce = [NSNumber numberWithInt:2]; // Works fine 

aber dies wird nicht berücksichtigt guter Objective-C-Stil.

The Objective-C Programming Language doc enthält eine „historische Note“ dazu:

Note: Historically, the interface required declarations of a class’s instance variables, the data structures that are part of each instance of the class. These were declared in braces after the @interface declaration and before method declarations: [...] Instance variables represent an implementation detail, and should typically not be accessed outside of the class itself. Moreover, you can declare them in the implementation block or synthesize them using declared properties. Typically you should not, therefore, declare instance variables in the public interface and so you should omit the braces.

Dies ist eine ziemlich große Veränderung (ich war wirklich überrascht, dass es keine Syntax für ivars in @interface mehr in diesem Dokument erklärt gegeben), aber Es ist definitiv zum Besseren. Sie sollten deklarierte Eigenschaften verwenden. Sie machen das Richtige und machen Ihren Code sauberer und sicherer.

+0

das ist wirklich eine gute Antwort!Was ich jetzt mit der Ankunft von ARC frage, ist es nicht ein bisschen "sicherer", Propeties zu verwenden, anstatt Ivars behalten und freigeben zu müssen, und dabei '[newCrunk retain] betrachten; [crunk release]; 'in deiner Probe? –

+0

Ja, diese Methode ist jetzt völlig unnötig (und mit ARC, illegal, so zu schreiben). Das war nur ein Beispiel dafür, wie es in der Vergangenheit gemacht wurde. –

+0

allright =) Ich habe es jetzt dank all Ihrer Antworten hier verstanden. danke Iulius für das klarste und vollständigste von ihnen und dafür, dass du dir die Zeit genommen hast, sogar nach dem historischen Ton zu suchen. es ist sehr geschätzt =) –

2

Wenn Sie schreiben:

@synthesize name; 

ein Ivar Namen erstellt, und es hat den gleichen Namen wie die Eigenschaft. So können Sie mit oder ohne sich darauf zugreifen.

In Wirklichkeit, wenn Sie schreiben

self.name = @"hello"; 

Sie die Eigenschaft zugreifen, und wenn Sie

name = @"hello"; 

Sie den Zugriff auf den Ivar schreiben. Die meisten Leute (einschließlich mir) werden Ihnen raten, nicht direkt auf Ihre Ivars zuzugreifen, es sei denn, es ist wirklich das, was Sie wollen: zum Beispiel, wenn Sie einen benutzerdefinierten Setter oder Getter für die Eigenschaft erstellen. Sonst immer Zugriff auf die Eigenschaft mit Selbst.

In meinem Fall mache ich immer:

@synthesize name = _name; 

Der Vorteil dieses Ansatzes besteht darin, dass, wenn Sie sich selbst zu schreiben vergessen, anstatt die Ivar des Zugriffs Sie erhalten eine Fehlermeldung angezeigt, dass der Ivar Name nicht der Fall ist existieren.

+0

das ist ein kluger Gedanke =) definierst du den ivar explizit in der Headerdatei oder lässt du ihn einfach implizit synthetisieren? –

+0

keine Notwendigkeit, es in die Header-Datei zu setzen, synthetisieren wird es für Sie erstellen! – Zalykr

2

Sie sollten niemals direkt von außerhalb einer Klasse auf Ivars zugreifen. Das ist die Hauptfunktion von Eigenschaften - Definieren von Zugriffsmethoden für die Verwendung durch andere Objekte. Es ist jedoch auch eine gute Methode, Ihre Accessoren aus derselben Klasse zu verwenden - auf diese Weise können Sie sicherstellen, dass entsprechende Nebenwirkungen auftreten (die Speicherverwaltung ist ein offensichtliches Beispiel, wenn Sie ARC nicht verwenden).

Also, Methode 3 ist in der Regel falsch. Methode 1 entspricht in etwa der Methode 2 - also hinter den Kulissen ist die Laufzeit im Grunde, die ein ivar für Sie erstellt. Beachten Sie auch, dass Sie den Namen des Ivar einstellen, auch wenn Sie es nicht explizit definiert haben:

@interface{ 
//No ivar here! 
} 
@property (...) Type *name; 
@synthesize name = ivarName; 
+0

das wusste ich nicht. Wenn ich also dem ivar implizit einen anderen Namen als die Eigenschaft gebe, kann ich mit 'self.name' und direkt mit' ivarName' darauf zugreifen und von außen werde ich 'setName' verwenden und die Eigenschaft verwenden. –

+1

Ja, obwohl '[self name]' und 'self.name' in der Regel die besten Optionen sind * sogar innerhalb der gleichen Klasse *. – andyvn22

0

Ab dem zweiten Link geliefert, Property vs. ivar in times of ARC, der Kommentar von Denis Mikhaylov auf der akzeptierte Antwort ist sehr aufschlussreich. Er weist darauf hin, dass mit Ihrem Fall 3, dass Sie die iVar durch zugreifen:

classInstance->iVar = @"New value" 

Aber das ist eine schlechte Praxis betrachtet. Also würde ich neu formuliert Ihren Punkt als:

Only with a property should an ivar be set from 'outside'