2009-06-09 5 views
2

Noch ein wenig verwirrt über Objective-C-Speicherverwaltung. Ich denke, dass meine Verwirrung davon herrührt, was genau die Autorelease bedeutet.Objective-C Setter Speicherverwaltung

Nun, was soll ich mit dem accountDictionary in der SetAccountDictionary-Methode meines View-Controllers tun? Gerade jetzt setze ich die Instanzvariable "accountDictionary" auf was auch immer zurückgegeben wird. Soll ich es auf eine beibehaltene setzen und dann die zurückgegebene freigeben? Wie sollte mein Setter-Codeblock aussehen, wenn die propertyList-Methode von NSString automatisch freigegeben wird?

Übrigens, wenn ich dieBackendResponse freigeben, verliere ich das accountDictionary? Ich nehme an, nicht ...

Antwort

14

Das Aufrufen [objectInstance autorelease] fügt dem aktuellen NSAutoreleasePool ein Objekt hinzu. Wenn dieser Pool eine Nachricht drain empfängt, sendet es eine release an alle Objekte in dem Pool. Wenn eines der RetainCount-Objekte dieser Objekte 0 erreicht, werden sie an diesem Punkt freigegeben. Der Zweck der Autorelease ist es, Ihnen zu erlauben, ein Objekt zu markieren, das "irgendwann in der Zukunft" veröffentlicht werden soll. Dies ist besonders nützlich für Dinge wie Methoden, die ein neu zugewiesenes Objekt zurückgeben, es aber freigeben wollen, so dass der Aufrufer nicht das Eigentum des zurückgegebenen Objekts übernehmen muss. Ein Verfahren könnte wie folgt aussehen:

- (id)myMethod { 
    id myObj = [[SomeClass alloc] init]; 

    ... 

    return [myObj autorelease]; 
} 

Der Anrufer von myMethod würde dann retain der Rückgabewert, wenn sie das Eigentum an dem zurückgegebene Wert nehmen wollten oder es ignorieren, wenn nicht. Wenn der aktuelle NSAutoreleasePool leer ist, wird myObj eine Freigabenachricht erhalten. Wenn es keine anderen Objekte besitzt (d. H. Es hat eine retain Nachricht gesendet), wird es freigegeben.

All dies wird im Cocoa Memory Management Programming Guide erklärt. Selbst wenn Sie es bereits gelesen haben, ist es immer eine andere Lektüre wert.

Also, Ihre Fragen zu beantworten:

Zunächst sollten Sie theBackendResponse freigeben. Sie werden Speicher verlieren, wenn Sie dies nicht tun. Sie müssen nicht wissen, was accountDictionary mit dem String tut: Wenn es einen Verweis behalten muss, hat es theBackendResponse behalten. Sie haben ein Eigentumsrecht an theBackendResponse, weil Sie alloc 'd es, so müssen Sie dieses Eigentum (über release oder indirekt über autorelease) aufgeben.

Zweitens müssen Sie das Argument beibehalten oder in setAccountDictionary: kopieren, wenn Sie einen Verweis auf das Objekt bzw. den Wert beibehalten möchten.Die Standard-Setter-Methode sieht ungefähr so ​​aus (vorausgesetzt, Sie brauchen keine Atom Semantik):

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

Da Sie mit zu sein scheinen:

-(void)setAccountDictionary:(NSDictionary*)newDict { 
    if(newDict != accountDictionary) { 
    id tmp = accountDictionary; 
    accountDictionary = [newDict copy]; //Since newDict may be mutable, we make a copy so that accountDictionary isn't mutated behind our back. 
    [tmp release]; 
    } 
} 

Sie auch release accountDictionary im dealloc Verfahren erinnern müssen NSViewController, ich nehme an, Sie sind auf Leopard (OS X 10.5) in diesem Fall sollten Sie wahrscheinlich verwenden und die @synthesize d Getter/Setter wenn möglich. Um dies zu tun, fügen Sie eine

@property (copy,readwrite) NSDictionary * accountDictionary; 

Erklärung zur Klasse @interface. Und fügen Sie eine @synthesize accountDictionary; Direktive in den @implementation Block für Ihre Controller-Klasse hinzu.

+0

Beeindruckende Antwort. –

+0

Fantastisch, danke. Jetzt verstehe ich. Ich bin eigentlich auf dem iPhone, mit UIViewControllers, aber offensichtlich gilt Objective-C 2.0 noch. Ich werde keine synthetischen Getters/Setter für diesen verwenden, aber ich werde in der Zukunft. Danke noch einmal! – AriX

+0

Dies ist ein wenig falsch, Sie sollten das alte Objekt niemals freigeben, bevor Sie das neue Objekt behalten/kopieren. Wenn 'accountDictionary' sich auf' newDict' bezieht, wird der Aufruf von 'release' zuerst ausgelöst.Ich gebe eine alternative Lösung als Antwort an, da ich keinen mehrzeiligen Code hinzufügen kann –

2

Apple beschreibt mehrere Konzepte bei der Implementierung von Accessoren: Memory Management Accessor Methods
Wenn Sie Objective-C 2.0 verwenden können, würde ich mit Eigenschaften und Punktsyntax gehen. Eigenschaften sind neu in Objective-C 2.0 und bieten Auto-Accessor-Generierung.
In der .h Datei:

@property (retain) NSDictionary* accountDictionary; 

Bei der Umsetzung:

@synthesize accountDictionary; 

Synthesize Accessormethoden für Ihre NSDictionary erzeugt. (Wenn Sie Ihre eigene Implementierung bereitstellen möchten, können Sie das auch tun)

+0

Ich könnte das tun, aber es hilft mir nicht wirklich zu verstehen, was im Hintergrund passiert :) – AriX

4

Im Allgemeinen sollte sich ein Objekt oder eine Methode nicht darum kümmern, wie ein anderer Speicher verwaltet. Die Tatsache, dass jemand anderes etwas autoreleased hat, ist für dich irrelevant. Es ist einfacher, an das Konzept Besitz zu denken. So retain und einige andere Methoden behaupten, Eigentum, und release und autorelease geben Sie es auf. Wenn ein Objekt einen Verweis zu einem anderen Objekt behalten muss, sollte es so lange Besitz beanspruchen, wie es benötigt wird. Daher behalten oder kopieren Setter-Methoden entweder den neuen Wert oder geben den alten Wert frei oder geben ihn wieder frei.

Ich empfehle dringend zu lesen the Cocoa memory management guidelines. Sie sind nicht so lang oder kompliziert, und es ist sehr wichtig, sie zu verstehen.

+0

OK. Ich habe sie eigentlich nie gelesen, werde jetzt tun: p – AriX

3

Die Set-Accessor-Methode sollte immer copy/retain den ankommende Wert vor dem alten, in dem Fall der Freigabe, wo der alte Wert das einzige Objekt, das den neuen Wert besitzt:

-(void)setAccountDictionary:(NSDictionary*)newDict { 
    id old = accountDictionary; 
    accountDictionary = [newDict copy]; 
    [old release]; 
} 

Wenn accountDictionary zu newDict bezeichnet und der Retain-Zählerstand für newDict war 1, der Aufruf an vor dem Aufruf an [newDict copy] würde dazu führen, dass der Retain-Zähler auf 0 gesetzt wird und daher newDict freigeben.

Als Beispiel für einen falschen Code, wo wir das alte Wörterbuch lösen und kopieren Sie dann das neue Wörterbuch:

-(void)setAccountDictionary:(NSDictionary*)newDict { 
    [accountDictionary release]; 
    accountDictionary = [newDict copy]; 
} 

und haben den folgenden Code:

NSDictionary *dict = [obj accountDictionary]; 
[obj setAccountDictionary:dict]; 

Es gekünstelt, aber es zeigt, dass im Setter accountDictionary und newDict auf dieselbe Instanz verweisen. Wenn die Retain-Anzahl 1 ist, verringert die Zeile die Retain-Anzahl auf 0 und gibt somit die Instanz aus dem Speicher frei. [newDict copy] verweist jetzt auf eine ungültige Instanz.

+0

+1 Einverstanden. Können Sie ein Beispiel geben, in dem diese Art von Situation auftreten kann? – Stunner