2009-04-16 19 views
2

Ich weiß, dass, wenn Sie Folgendes tun Sie ganz sicher ein Speicherleck haben:Ist dies ein Ziel-C-Speicherleck?

id foo = [[NSObject alloc] init]; 
foo = nil; 

Aber was, wenn Sie self.foo verwenden, eine Eigenschaft mit behalten? Und Ihr Code sieht stattdessen wie folgt aus:

foo = [[NSObject alloc] init]; 
self.foo = nil; 

Ist das noch ein Speicherverlust, da die Zugriffs den Speicher freigibt, bevor es auf Null einstellen?

Antwort

4

self.foo = nil würde übersetzen in

[nil retain] 
[foo release] 
foo = nil 

Es gibt keine undichte Stelle hier Speicher ist.

2

Nein, das zweite Beispiel ist kein Speicherleck. In der Tat, das ist, wie ich mit retain Eigenschaften in meiner dealloc Methode umgehen. Es ist nur viel sauberer.

Das einzige, was Sie müssen vorsichtig sein, etwa ist dafür, dass nicht

self.foo = [[NSObject alloc] init]; 

schreiben oder sonst werden Sie doppelt behalten das Objekt und mit einem Speicherverlust enden.

+4

Beachten Sie, dass die Verwendung von Eigenschaften in dealloc normalerweise nicht empfohlen wird, wenn die Zugriffsmethode geändert wird, um einen anderen ivar (der bereits freigegeben wurde) zu ändern. Ich benutze stattdessen nur Release. –

+0

@Alex: +1 für eine ausgezeichnete Warnung, aber -1 für den Vorschlag, self.foo = nil in einer Dealloc-Methode zu verwenden! –

+2

@eJames self.foo = nil ist die Art, wie Apple es ursprünglich in der dealloc-Methode empfohlen hat und überall im Beispielcode ist. –

0

Ich denke nicht, so dass self.foo = nil Sie im Wesentlichen die Setter verwenden und die Speicherverwaltung kostenlos erhalten.

1

Eigenschaften machen Ihren Code wie Aufgabe aussehen, aber in Wirklichkeit sind sie die gleichen wie traditionelle Accessor-Methoden, die Sie selbst vor Obj-C 2.0 geschrieben haben. Mit Eigenschaften erzeugt Obj-C einfach die Accessor-Methoden, die hinter den Kulissen für Sie stehen, und verwendet stattdessen die Schlüsselwörter, die Sie in der Deklaration angeben (vorausgesetzt, Sie verwenden @synthesize und schreiben Sie nicht Ihre eigenen Accessor-Methoden).

1

Nein, es gibt kein Speicherleck. Der Code in Ihrem zweiten Beispiel ist logisch äquivalent zu

foo = [[NSObject alloc] init]; 
[nil retain]; 
[foo release]; 
foo = nil; 

weil die @synthesized Setter ist außerhalb LogiCall entspricht

- (void)setFoo:(id)newFoo { 
    [newFoo retain]; 
    [foo release]; 
    foo = newFoo; 
} 

Es ist erwähnenswert, dass Einstellung foo direkt ist wahrscheinlich nicht etwas, was Sie tun wollen von eine Init-Methode. Wenn Sie foo direkt einen Wert zuweisen, umgehen Sie die automatische KVO-Benachrichtigung (Sie müssten Ihre Zuordnung in ein willChangeValueForKey:/didChangeValueForKey:-Paar einbinden) und Sie brechen das Verhalten einer Unterklasse, wenn sie die setFoo:-Methode überschreibt und alle Änderungen von foo erwartet geh durch den Setzer.

Sie direkt zuweisen foo in einer init-Methode, weil die setFoo: Methode oder eine Unterklasse außer Kraft gesetzt setFoo: Methode Nebenwirkungen kann oder hat, hängt von der Instanz vollständig initialisiert.

Ebenso würden Sie [foo release] statt self.foo = nil; in der -dealloc Methode aus den gleichen Gründen verwenden.

1

Alle bisherigen Antworten gehen davon aus, dass "foo" in der ersten Zeile des zweiten Beispiels die Instanzvariable hinter der foo-Eigenschaft ist.Dies ist das Standardverhalten.

Wenn die foo, der die erste Zeile zuweist, eine lokale Variable ist, dann ist die foo Eigenschaft irrelevant, und Sie werden das Objekt verlieren, wenn Sie es später in der Methode freigeben. Wenn die eine Instanzvariable ist, aber die foo -Eigenschaft tatsächlich durch eine andere Instanzvariable oder gar keine Instanzvariable unterstützt wird, dann schreiben Sie (a) schwer zu wartenden Code und (b) kann es sein ein Leck sein.

Schließlich Echo der bisherigen Antworten: Wenn foo die Instanzvariablen die foo Eigenschaft sichern, dann ist dies kein Leck, da die setFoo: Methode, die Sie in der zweiten Zeile rufen Sie das Objekt freigeben, die Sie setzen in den foo Instanzvariable in der ersten Zeile.

0

Da sonst niemand zu haben scheint bemerkt: Es ein Leck sein könnte.

Ich gehe davon aus, dass foo ist sowohl ein Ivar und eine retain Eigenschaft:

@interface Foo : NSObject { 
    NSObject * foo; 
} 
@property (nonatomic, retain) NSObject * foo; 
@end 

Angenommen, Ihr Code etwa wie folgt aussieht:

-(void)bar { 
    foo = [[NSObject alloc] init]; 
    self.foo = nil; 
} 

Das an sich nicht undicht bereitgestellt foo wurde nicht mit beginnen. Das bedeutet nicht, es nicht undicht wird - sagen wir, Sie etwas mehr Code hinzu:

-(void)baz { 
    self.foo = [[NSObject new] autorelease]; 
} 

-(void)fubar { 
    [self baz]; 
    [self bar]; 
} 

Sachen wie foo = [[Foo alloc] init] in init -Methoden im Allgemeinen sicher ist, weil davon ausgegangen, dass Sie nur eine von ihnen nennen, so foo ist garantiert am Anfang nil. Überall sonst muss man etwas vorsichtiger sein.

Verwandte Themen