Warum entsteht dadurch ein Speicherleck (iPhone)?

8
%Vor%

Die erste Codezeile erzeugt einen Speicherverlust, selbst wenn Sie [self.editMyObject release] in der Dealloc-Methode der Klasse ausführen. self.editMyObject ist vom Typ MyObject. Die zweite Zeile verursacht kein Speicherleck. Ist die erste Zeile falsch oder gibt es eine Möglichkeit, den Speicher freizugeben?

    
4thSpace 04.03.2009, 23:36
quelle

6 Antworten

10

Das richtige Verhalten hängt von der Deklaration der Eigenschaft editMyObject @ ab. Angenommen, es ist als

delcared %Vor%

oder

%Vor%

dann behält oder kopiert die Zuordnung über self.editMyObject = das zugeordnete Objekt. Da [[MyObject alloc] init] ein beibehaltenes Objekt zurückgibt, das Sie als Aufrufer besitzen, haben Sie ein zusätzliches Behalten der MyObject-Instanz und es wird daher undicht, es sei denn, es gibt eine passende Version (wie im zweiten Block). Ich würde vorschlagen, dass Sie den Memory Management Programming Guide lesen. 2].

Ihr zweiter Codeblock ist korrekt, vorausgesetzt, die Eigenschaft wird wie oben beschrieben deklariert.

ps. Sie sollten [self.editMyObject release] nicht in einer -dealloc -Methode verwenden. Sie sollten [editMyObject release] aufrufen (unter der Annahme, dass die @property-Unterstützung die Bezeichnung editMyObject hat). Aufrufen des Accessors (über self.editMyObject ist sicher für @synthesized Accessoren, aber wenn ein überschriebener Accessor auf den Objektstatus angewiesen ist (der am aufrufenden Speicherort in -dealloc möglicherweise nicht gültig ist oder andere Nebeneffekte verursacht, liegt ein Fehler vor den Accessor aufrufen.

[2] Regeln für Objektbesitz in Cocoa sind sehr einfach: Wenn Sie eine Methode aufrufen, die alloc oder copy in ihrer Signatur hat (oder +[NSObject new] verwendet, was im Grunde äquivalent zu [[NSObject alloc] init] ist), dann Sie "besitzen" das Objekt, das zurückgegeben wird, und Sie müssen Ihren Besitzbesitz mit einem release ausgleichen. In allen anderen Fällen besitzen Sie nicht das Objekt, das von einer Methode zurückgegeben wird. Wenn du es behalten möchtest, musst du die Eigentumsrechte mit retain übernehmen und später die Eigentumsrechte mit release freigeben.

    
Barry Wark 04.03.2009, 23:47
quelle
8

Ihre Eigenschaft wird als "beibehalten" deklariert, dh das übergebene Objekt wird automatisch beibehalten.

Da Ihr Objekt bereits eine Referenzzahl von eins von alloc / init hatte, gibt es dann zwei Referenzen und ich nehme nur eine Version (in Ihrem Destruktor) an.

Grundsätzlich macht der Aufruf von self.editMyObject dies wirklich;

%Vor%     
Andrew Grant 04.03.2009 23:44
quelle
4

Nach Konvention in Cocoa und Cocoa-touch wird jedes Objekt, das mit [[SomeClass alloc] initX] oder [SomeClass newX] erstellt wurde, mit einer Retain-Anzahl von eins erstellt. Sie sind dafür verantwortlich, [someClassInstance release] aufzurufen, wenn Sie mit Ihrer neuen Instanz fertig sind, normalerweise in Ihrer dealloc -Methode.

Schwieriger wird es, wenn Sie Ihr neues Objekt einer Eigenschaft anstatt einer Instanzvariablen zuweisen. Die meisten Eigenschaften sind als retain oder copy definiert, was bedeutet, dass sie entweder die Retain-Anzahl des Objekts erhöhen, wenn sie festgelegt werden, oder eine Kopie des Objekts erstellen, wobei das Original unberührt bleibt.

In Ihrem Beispiel haben Sie dies wahrscheinlich in Ihrer .h -Datei:

%Vor%

Also in Ihrem ersten Beispiel:

%Vor%

Wenn Sie Ihre neue Instanz von MyObject mit alloc / init erstellen, hat sie eine Retain-Anzahl von eins. Wenn Sie die neue Instanz self.editMyObject zuweisen, rufen Sie tatsächlich die Methode -setEditMyObject: auf, die der Compiler für Sie erstellt, wenn Sie @synthesize editMyObject verwenden. Wenn der Compiler self.editMyObject = x sieht, wird er durch [self setEditMyObject: x] ersetzt.

In Ihrem zweiten Beispiel:

%Vor%

Sie halten Ihr neues Objekt lange genug fest, um es freizugeben, sodass die Anzahl der Retains ausgeglichen ist (vorausgesetzt, Sie geben es in Ihrer dealloc -Methode frei).

Siehe auch Cocoa-Strategie für die Zeiger- / Speicherverwaltung

    
Don McCaughey 05.03.2009 00:37
quelle
3

Die erste Version erstellt ein Objekt ohne eine passende Version. Wenn Sie das Objekt zuweisen, bedeutet dies, dass Sie Eigentümer dieses Objekts sind. Ihr Setzer behält vermutlich das Objekt (wie es sollte), was bedeutet, dass Sie das Objekt nun zweimal besitzen. Sie benötigen die Freigabe, um die Objekterstellung auszugleichen.

Sie sollten das Cocoa-Handbuch zur Speicherverwaltung lesen, wenn Sie Cocoa bei verwenden möchten alle. Es ist nicht schwer, wenn du es erst einmal gelernt hast, aber es ist etwas, was du lernen musst oder du wirst viele Probleme haben.

    
Chuck 04.03.2009 23:44
quelle
1

Alle anderen haben bereits geklärt, warum es zu einem Speicherleck kommt. Daher werde ich kurz darauf eingehen, wie man die Variable 'temp' vermeidet und trotzdem einen Speicherverlust verhindert:

%Vor%

Dies wird Ihre (behalten) Eigenschaft als alleiniger Besitzer des neuen Objekts verlassen. Genau das gleiche Ergebnis wie in Ihrem zweiten Beispiel, aber ohne das temporäre Objekt.

    
e.James 05.03.2009 00:34
quelle
0

Es wurde vereinbart und erklärt, dass der folgende Code kein Leck hat (Annahme von @property retain und @synthesize für editMyObject):

%Vor%

Frage: Ist mit dem folgenden Code, der keinen temporären Zeiger verwendet, etwas falsch?

%Vor%

Für mich sieht das gut aus.

    
rudifa 23.10.2009 19:42
quelle