2010-10-28 6 views
7

Ich möchte verstehen, wie Sie die Parameter von Eigenschaften (Accessoren) einstellen.Initialisierer, Eigenschaften, Accessoren und kopieren/behalten/readonly

Ich nahm den folgenden Code aus einem Beispiel für Kal-Kalender.

// Holiday.h 

@interface Holiday : NSObject 
{ 
    NSDate *date; 
    NSString *name; 
    NSString *country; 
} 

@property (nonatomic, retain, readonly) NSDate *date; 
@property (nonatomic, retain, readonly) NSString *name; 
@property (nonatomic, retain, readonly) NSString *country; 

- (id)initWithName:(NSString *)name country:(NSString *)country date:(NSDate *)date; 

@end 

// Holiday.m 

#import "Holiday.h" 

@implementation Holiday 

@synthesize date, name, country; 

- (id)initWithName:(NSString *)aName country:(NSString *)aCountry date:(NSDate *)aDate 
{ 
    if ((self = [super init])) { 
    name = [aName copy]; 
    country = [aCountry copy]; 
    date = [aDate retain]; 
    } 
    return self; 
} 

- (void)dealloc 
{ 
    [date release]; 
    [name release]; 
    [country release]; 
    [super dealloc]; 
} 

@end 

1) Die Eigenschaften sind auf retain gesetzt, aber da der Setter nicht die retain macht hier keinen Sinn verwendet werden können.

2) Zusätzlich werden in der Methode die Werte mit copy eingestellt. Warum definieren Sie nicht direkt die Eigenschaften mit copy und verwenden die Accessor-Methoden?

@property (nonatomic, copy) NSString *name; 
// ... 
self.name = aName; 

3) Benötige ich die readonly hier? Ich weiß nicht, warum sie hier benutzt werden. Wenn ich copy zusammen mit dem Setzer verwenden würde, verbietet mir die readonly, den Wert einzustellen, weil es keinen Setzer gibt.

4) In der initWithName Methode wird manchmal copy und manchmal retain verwendet. Ich würde vorschlagen, hier immer copy zu verwenden, da der Wert später nicht geändert werden sollte.

5) Was kann ich mich erinnere ist, dass es zu copy/retain im initWithName und release im dealloc Methode ist OK. Wie würden Sie in diesem Beispiel retain, copy und readonly vorschlagen?

Antwort

13

ETA: @DougW richtig weist darauf hin, dass eine Eigentumsform Eigentum (assign/retain/copy) wirkt sich nicht auf den Getter. Es wirkt sich immer noch auf den Setter aus. Für readonly Typen ist dies wichtig, wenn Sie den readonly-Teil der Deklaration in einer Klassenerweiterung überschreiben, sodass Sie den Setter innerhalb Ihrer Implementierung verwenden können. Eine Überschreibungseigenschaft der Klassenerweiterung darf nur den readonly-Status der Eigenschaft ändern, daher muss der Rest der Klasse - also die Atomizitäts- und Besitzertypen - in der Kopfzeile entsprechend deklariert werden. Selbst wenn Sie die Property jetzt nicht überschreiben, könnten Sie dies in Zukunft tun, also können Sie genauso gut dokumentieren, wie der Speicher für Sie verwaltet werden soll, indem Sie zunächst die richtige Option verwenden.

Automatische Referenzzählung (ARC) ändert die Laufzeitimplementierungsdetails, indem die eigenen Speicherverwaltungsregeln über die klassischen Refcount-Regeln gelegt werden. Die Regeln und Hinweise für die Konfiguration Ihrer Eigenschaften bleiben jedoch gleich.


Warum retain mit readonly verwenden? Wenn Sie eine Immobilie als retain, die synthetisierte Accessor markieren tut etwas wie folgt aus:

/* getter for retain property */ 
- (NSString *)name { 
    return [[name retain] autorelease]; 
} 

Nun, wenn das Objekt, das Sie -name gesendet den Namen ändert, während Sie immer noch in Gebrauch ist, wird der anrufende Code noch haben ein gültiger Verweis auf eine Zeichenfolge.Wenn Sie es als assign erklärt, obwohl, würde es so sein:

/* getter for assign property */ 
- (NSString *)name { 
    return name; 
} 

Nun, sobald Name durch das Objekt geändert wird, wird es freigegeben werden muß, um ein Leck zu vermeiden, die die Berufung ungültig werden Code-Referenz. Die retain/copy/assign ist wirklich eine Speicher-Management-Richtlinie: retain/copy sagt: "Ich verspreche, dass ich einen Verweis auf das Original/eine Kopie des Wertes, den ich hier zur Verfügung stellen", während assign sagt, "Ich habe nur der Wert und behaupten, keinen Bezug darauf zu haben. "

Wenn der Wert keine Speicherverwaltung benötigt, z. B. eine einfache int, dann ist assign sinnvoll. Wenn Sie absichtlich ein Objekt wie einen Delegaten nicht beibehalten, ist assign sinnvoll. In den meisten anderen Fällen benötigen Sie jedoch retain oder copy.

Weiter kann die Implementierungsdatei nur den Teil readwrite/readonly einer Eigenschaftsdeklaration überschreiben, nicht den Speicherverwaltungsteil. Wie erklärt, kann die .m Datei:

@interface Holiday (/*class extension*/) 
@property(nonatomic, retain, readwrite) NSDate *date; 
/* override other properties to make them readwrite... */ 
@end 

Nicht-öffentliche Setter für die überschriebene Eigenschaft Erklärungen werden dann zusammen mit den öffentlichen Accessoren synthetisiert werden.

Warum nicht Setter/Accessoren während -init verwenden? Da Setter/Accessoren häufig KVO-Benachrichtigungen ausführen, die Sie vermeiden möchten, während Ihr Objekt nicht vollständig initialisiert wird, z. B. -init (wenn es auf dem Weg zur vollständigen Initialisierung zur Hälfte initialisiert wird) und -dealloc (wenn es halb initialisiert ist) Möglichkeit, vollständig uninitialisiert zu werden).

Warum copy mit readonly verwenden? Als Antwort auf Ihre erste Frage: weil, wenn copy gegenüber retain gegenüber assign betrifft sowohl die Setter und die Getters. Eine Kopie Getter würde wie folgt aussehen:

/* getter for copy property */ 
- (NSString *)name { 
    return [[name copy] autorelease]; 
} 

Warum manchmal copy und manchmal retain?copy wird normalerweise mit Wertobjekten verwendet (passive Objekte, die einen Wert darstellen); retain wird normalerweise mit anderen Objekten verwendet. Manchmal kommen Effizienzprobleme ins Spiel (höchstwahrscheinlich zu früh ...), und Sie könnten sich dafür entscheiden, retain zu verwenden, wo Sie normalerweise copy verwenden würden.

Wie würden Sie copy/retain zusammen mit readonly hier verwenden? So ziemlich wie sie es taten. Ich würde die Deklarationen in einer Klassenerweiterung überschreiben, so dass ich Setter verwenden kann, um die Werte der Eigenschaften außerhalb von -init und -dealloc zu ändern, wo ich nur den Variablenzugriff der direkten Instanz verwenden würde. Ich würde auch nil aus dem ivars nach ihnen in -dealloc Freigabe, zum Beispiel

[name release], name = nil; 

Dies hilft, das Senden von Nachrichten zu vermeiden oder auf andere Weise Referenzierung ein bereits freigegeben Objekts.

+0

** nichtatomare ** beibehalten Eigenschaften geben Sie einfach den Zeiger zurück. Sie tun ** nicht das behalten, Autorelease-Ding. Siehe den Abschnitt ** Atomizität ** der Dokumentation http://developer.apple.com/library/ios/# Dokumentation/Kakao/Konzeptionelle/ObjectiveC/Artikel/ocProperties.html – JeremyP

+0

@ JeremyP: Guter Ruf. Die Entscheidung, bei nicht-atomaren Zugriffsmethoden die "[[foo retain] Autorelease"] nicht beizubehalten, macht Sinn: Wenn Sie den Wert länger als den aktuellen Runloop-Zyklus festhalten, sollten Sie ihn selbst behalten. Wenn Sie 'nichtatomisch' verwenden, heißt das grundsätzlich, dass die Thread-Sicherheit keine Rolle spielt. Wenn Sie sich nicht um die Threadsicherheit kümmern müssen, wird kein Code neben Ihrem ausgeführt, während Sie den Rückgabewert vom Accessor verwenden. Daher ist es für den Accessor nicht notwendig, '[[foo retain] autorelease]' 'auszuführen . –

+0

@ Jeremy: Ich würde so weit gehen, zu sagen, dass Sie mit nichtatomaren Mitteln sagen, dass Robustheit kein Problem ist - oder weniger als Leistung betrifft. Das Festlegen von Eigenschaften auf nichtatomisch, ohne zuerst den Code zu profilieren, zählt als vorzeitige Optimierung in meinem Buch. – JeremyP

Verwandte Themen