4 Stimmen

Verwendung von Accessor-Methoden zum Setzen von iVars?

Zunächst sah ich mir die Art und Weise an, wie "pickerData" gesetzt wird, und fragte mich, warum man es nicht einfach direkt zuweisen kann (wie in METHOD_002), aber dann stellte ich fest, dass ich eigentlich die von mir definierten Zugriffsmethoden verwenden und die Instanzvariablen nicht direkt setzen sollte. Verstehe ich das richtig, dass METHOD_001 ein besserer Weg ist, dies zu tun?

@property(nonatomic, retain) IBOutlet NSArray *pickerData;

METHOD_001

-(void)viewDidLoad {
    NSLog(@"VIEW: Single ... Loaded");
    NSArray *dataArray = [[NSArray alloc] initWithObjects:@"A", @"B", @"C",nil];
    [self setPickerData:dataArray];
    [dataArray release];
    [super viewDidLoad];
}

-(void)dealloc {
    [pickerData release];
    [super dealloc];
}

OR METHOD_002

-(void)viewDidLoad {
    NSLog(@"VIEW: Single ... Loaded");
    if(pickerData != nil) [pickerData release];
    pickerData = [[[NSArray alloc] initWithObjects:@"A", @"B", @"C", nil] retain];
    [super viewDidLoad];
}

-(void)dealloc {
    [pickerData release];
    [super dealloc];
}

EDIT_001:

Zunächst einmal habe ich die "nil"-Werte hinzugefügt, um die NSArrays zu beenden, da ich von C komme, vergesse ich das immer, mein Fehler. Außerdem hast du Recht, ich habe in METHOD_002 nicht berücksichtigt, dass pickerData bereits gesetzt sein könnte und dadurch das alte Objekt verloren geht. Sobald man anfängt, diese Probleme zu bemerken und den Code zu korrigieren, sieht es so aus, als ob METHOD_001 die beste Idee ist. Oder man verwendet die Eigenschaft einfach direkt, wie Vladimir und eJames bemerkten.

self.pickerData = [NSArray arrayWithObjects: @"A", @"B", @"C", nil];

EDIT_002:

Vielen Dank für alle Hinweise und Kommentare, für jetzt werde ich mit METHOD_001 bleiben, ich könnte genauso gut NSArrayWithObjects verwenden: aber ich versuche, Speicherverbrauch niedrig zu halten, indem ich Dinge selbst so schnell wie möglich freigebe (nicht, dass es hier, aber für zukünftige Projekte zählt) Auch ich mag das Gefühl von self.pickerData, aber ich bin immer noch unsicher, wie ich über Punkt-Notation fühlen und haben für jetzt versucht, mit alten Stil-Objekte und Nachrichten wo möglich zu bleiben. Nochmals vielen Dank für die Hilfe.

gary

3voto

e.James Punkte 112528

Hier gibt es viele Themen zu behandeln, aber ich beginne mit dem empfohlenen Ansatz:

METHOD_003

-(void)viewDidLoad { 
    NSLog(@"VIEW: Single ... Loaded"); 
    self.pickerData = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; 
    [super viewDidLoad];
}

Anmerkung: Dank an Vladimir für die Erinnerung an die Null-Terminierung .

Nun zu den Details:

METHOD_001 tut genau dasselbe wie METHOD_003, benötigt aber ein paar Zeilen mehr Code.

METHOD_002 hat ein Speicherleck, weil Sie alloc das Array, und dann auch retain es. Dies ergibt eine Gesamtzahl von 2. Wenn Sie das Array in Ihrem dealloc Methode wird die Anzahl auf 1 reduziert, so dass das Array nicht aus dem Speicher freigegeben wird.

Selbst wenn Sie die zusätzlichen retain von METHOD_002, werden zwei sehr wichtige Dinge nicht getan:

  1. Es wird nicht die richtige KVC/KVO-Meldungen . Cocoa tut eine Menge von sehr bequemen Dinge hinter den Kulissen, wenn Sie eine Eigenschaft Accessor verwenden, so dass, wenn Sie einen guten Grund haben, nicht zu, mit den Accessoren ist sehr zu empfehlen.

  2. Es werden nicht automatisch alle alten Daten freigegeben, die in pickerData . Dies ist kein Grund zur Sorge in viewDidLoad aber wenn Sie eine andere Methode anwenden würden, wäre es würde Daher ist es am besten, sich die Verwendung der Accessoren anzugewöhnen, es sei denn, Sie haben einen besonderen Grund, dies nicht zu tun.

3voto

TechZen Punkte 64117

Sie sollten immer Accessors von Eigenschaften verwenden (was in Objective-C 2.0 bedeutet, dass Sie die self.property Notation).

Warum? Weil es eine automatische Zugriffskontrolle und eine Verwaltung des Lebenszyklus von Objekten ermöglicht. Die generierten Accessors können eine Menge Schutz bieten, wie z.B. Lesen/Schreiben, Kopieren, Beibehalten usw., die sonst viel manuellen Code erfordern. Wenn Sie Ihre eigenen Accessors schreiben, können Sie alle gewünschten Validierungen und Seiteneffekte einbauen.

(Vor Objective-C 2.0 galt das Schreiben von Accessors als hohe Kunst. Das kann es immer noch sein, wenn man das Potenzial voll ausschöpft.)

Sie sollten nur dann direkt auf Eigenschaften zugreifen, wenn Sie einen Accessor schreiben. Nehmen Sie zum Beispiel dieses gängige Muster:

@property(nonatomic, retain)  NSMutableArray *myObjects;
@synthesize myObjects;

-(NSMutableArray *) myObjects{
    if (myObect!=nil) {
        return myObect;
    }
    NSMutableArray *anArray=[[NSMutableArray alloc] initWithCapacity:1];
    self.myObject=anArray;
    [anArray release]
    return myObject;
}
  1. Dieser Accessor stellt sicher, dass myObjects nie null ist, was eine Menge von Boilerplate-nil-Tests im Rest Ihres Codes beseitigt.
  2. Sie können natürlich nicht anrufen self.myObjects (was in Wirklichkeit [self myObjects] ist) innerhalb des Accessors, ohne eine unendliche Rekursion zu erzeugen, also müssen Sie hier auf die rohe Variable zugreifen, aber...
  3. ...Sie können die (automatisch generierte) self.myObjects= (was in Wirklichkeit [self setMyObjects:anArray] ist), weil es eine völlig andere Methode ist. Wenn Sie sich die Interna von setMyObjects: ansehen, werden Sie sehen, dass es auch auf die Rohvariable zugreift.
  4. Wenn Sie die generierten Accessoren verwenden, self.myObjects= übernimmt für Sie das Einbehalten, Kopieren, Nilling usw., wenn Sie es aufrufen. Das einzige Mal, dass Sie release aufrufen müssen, ist beim dealloc. Dies allein wischt wahrscheinlich die Hälfte der Fehler, die Menschen in Objective-C machen, aus.

Außerhalb einer Accessor-Methode haben Sie dagegen keinerlei Vorteile, wenn Sie direkt auf die Eigenschaften innerhalb der klasseninternen Methoden zugreifen. Man spart sich lediglich einige Tastatureingaben und setzt sich dem Risiko schwer zu findender Fehler aus.

Wie aus den vorherigen Antworten hervorgeht, haben Sie mehrere Speicherfehler gemacht, indem Sie versucht haben, die Eigenschaft direkt zu verwalten. Hätten Sie jedes Mal den Accessor verwendet, wären Ihnen diese Fehler nicht unterlaufen. Zum Beispiel:

pickerData = [[[NSArray alloc] initWithObjects:@"A", @"B", @"C", nil] retain];

... jedes Mal genau richtig gehandhabt werden muss, während ...

self.pickerData = [[NSArray alloc] initWithObjects:@"A", @"B", @"C", nil];

... ist automatisch richtig.

Denken Sie daran, dass das ultimative Design-Ziel für jede Objective-C-Klasse ist, dass es perfekt modular und wiederverwendbar sein sollte. Das heißt, sie sollte ihren eigenen Speicher, ihre eigene Datenvalidierung und ihre eigenen Seiteneffekte verwalten. Accessors sind für diese Verwaltung absolut unerlässlich. Indem Sie jeden Zugriff auf eine Variable mit Logik ummanteln, stellen Sie sicher, dass (1) es sich um den Typ, den Bereich usw. handelt, den Sie erwarten, und (2) dass sie immer da ist, wenn Sie sie brauchen, (3) dass Sie alle Seiteneffekte des Schreibens oder Lesens der Variable kontrollieren können und (4) dass sie nicht ausläuft.

Ich kann die Vorzüge von Accessoires nicht genug loben. Ich könnte sogar ein kleines Lied schreiben ;-)

0voto

Sixten Otto Punkte 14771

Die größten Probleme mit Ihrer METHOD_002 sind: a) Sie behalten ein Array, das Sie bereits besitzen, was Sie nicht tun müssen (und wird das Array undicht), und b) Sie sind nicht für die Möglichkeit, dass pickerData möglicherweise bereits eine nicht nil Wert ( viewDidLoad kann während der Lebensdauer eines Controllers viele Male aufgerufen werden).

Aus stilistischen Gründen ist die erste Methode wahrscheinlich besser. Sie hätte (b) vermieden und kümmert sich im Allgemeinen um viele lästige Details, damit Sie es nicht tun müssen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X