2010-07-16 5 views
17

Ich habe das folgende Snippet einiges seeen:alloc + init mit synthetisierter Eigenschaft - führt dies dazu, dass die Retain-Anzahl um zwei erhöht wird?

In der Kopfzeile:

SomeClass *bla; 
@property(nonatomic,retain) SomeClass *bla; 

In der Implementierungsdatei:

@synthesize bla; 

und dann

self.bla = [[SomeClass alloc] init]; 

I denke, dass diese Zuweisung die Retain-Anzahl für 'bla' um zwei erhöht; einmal durch den Alloc/Init-Aufruf, dann durch den Retain, den wir über den synthetisierten Property Setter haben wollten.

Als Ergebnis ich normalerweise meine Eigenschaften wie folgt erklären:

In der Kopfzeile:

SomeClass *_bla; // note the underscore 
@property(nonatomic,retain) SomeClass *bla; 

In der Implementierungsdatei:

@synthesize bla = _bla; 

und dann

_bla = [[SomeClass alloc] init]; 

Pr meine ursprüngliche Annahme ist richtig - ich wäre interessiert zu hören, ob es einen "richtigen" Weg gibt, nämlich die Deklaration, Initialisierung und Speicherverwaltung von Immobilien?

+0

Zuerst willkommen zu Stack Overflow. Eines der Dinge, die bei Stack wichtig sind, ist es, Antworten zu akzeptieren, die für Sie funktionieren. Es ist wichtig für die Beantworter und für Ihren eigenen Ruf. – smathy

Antwort

8

Ja, Sie haben Recht - die Verwendung des synthetisierten Setter einer retain-Eigenschaft würde die Ref-Zählung für eine bereits vorhandene Instanz erhöhen (wie alloc impliziert).

Gehen Sie einfach mit dem zweiten Formular, das Sie in Ihrem initializers erwähnt:

_bla = [[SomeClass alloc] init]; 

... und erinnern sonst die Beibehaltungszähler zu beheben, zum Beispiel:

self.bla = [[[SomeClass alloc] init] autorelease]; 
8

Ich denke, dass diese Zuweisung erhöht die Retain-Anzahl für 'bla' um zwei;

Wahr.

ich interessiert wäre zu hören, ob es ‚richtige‘ Art und Weise ist es, dieses

Ihr letztes Stück Code zu tun, ist der richtige Weg, aber der Unterstrich wird nicht empfohlen. Die Eigenschaft und der Ivar können denselben Namen haben. Nur

@interface Foo : Bar { 
    SomeClass* bla; 
} 
@property (nonatomic, retain) SomeClass* bla; 
@end 

@implementation Foo 
@synthesize bla; 
-(id)init { 
    ... 
    bla = [[SomeClass alloc] init]; 
    ... 
} 
-(void)dealloc { 
    [bla release]; 
    ... 
    [super dealloc]; 
} 

ist genug.


können Einige Leute

SomeClass* foo = [[SomeClass alloc] init]; 
self.bla = foo; 
[foo release]; 

oder

self.bla = [[[SomeClass alloc] init] autorelease]; 

im -init Methode verwenden, aber ich es stark entmutigen, da dies unnötig viele Methoden aufruft, and you cannot guarantee the behavior of the setter.

+0

Wao - mein erster Post auf Stackoverflow, und zwei Antworten innerhalb von 5 Minuten. Danke euch beiden! – patschiboy

+6

Die beiden Muster, von denen Sie dringend abraten, sind in den meisten Fällen vollkommen akzeptabel und normal. Die Antwort, die Sie verknüpft haben, bezieht sich ** nur ** auf die Verwendung von Zugriffsmethoden, um Objekte in den 'init'- und' dealloc'-Methoden zu setzen. Überall sonst empfiehlt Apple immer die Zugriffsmethoden für den Zugriff auf Instanzvariablen. – JeremyP

+0

JeremyP hat Recht, und aus diesem Grund sollte dies nicht als richtige Antwort betrachtet werden. – Felixyz

3

Es sieht so aus, als ob das Kernproblem hier ein Missverständnis der Objektbesitzsemantik in Cocoa ist. Für jedes init, copy oder retain aufgerufene Objekt muss ein Aufruf an release oder autorelease erfolgen. Was passiert hier ist, dass der Anruf an init keinen übereinstimmenden Anruf an release oder autorelease hat.

Ich denke, was hier verwirrend ist, ist, dass die Punktnotation für die Eigenschaftszuordnung syntaktischer Zucker für einen Methodenaufruf ist. Es sieht also so aus, als wäre es nur eine Aufgabe, wenn es sich tatsächlich um einen Aufruf an einen Property Setter handelt.

self.bla = [[SomeClass alloc] init]; 

ist nicht das Gleiche wie:

bla = [[SomeClass alloc] init]; 

Erstere in übersetzt:

[self setBla: [[SomeClass] alloc] init]]; 

während letztere buchstäblich eine Zuordnung.

zu beheben Ihr Problem alles, was Sie wirklich, dass der Code sicher, tun müssen, ist, dass init Anrufe Anrufe autorelease so dass das behält Anzahl nach dem retain Aufruf des Setter verringert werden.

-3

Es gibt keine Doppelzählung. Der Setter, der durch synthetisieren erstellt wurde, macht eine Freigabe, bevor er einen Retain durchführt. Siehe Stanford-Klasse zu Zielklasse 3, wie auf der Apple-Website angegeben. Es ist auch erwähnenswert, dass im Falle von iBoutlets das Alloc-Init nicht benötigt wird, da es durch das Laden der XIB-Datei ausgeführt wird.

+0

Für falsch gewählt. [[xxx alloc] init] gibt ein Objekt mit einer Retain-Anzahl von 1 zurück, dem irgendwann entgegengewirkt werden muss. Wenn Sie das Ergebnis in einer beibehaltenen Eigenschaft speichern, setzen Sie die beibehaltene Eigenschaft sofort auf null, und Sie haben ein Speicherleck. – gnasher729