2010-07-16 12 views
17

Ho seeen il seguente frammento del tutto un po ':alloc + init con proprietà synthesized - fa sì che il conteggio dei ritardi aumenti di due?

Nell'intestazione:

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

Nel file di implementazione:

@synthesize bla; 

e poi

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

I pensa che questo incarico metta il conto dei ritardi per "bla" di due; una volta attraverso la chiamata alloc/init, quindi attraverso il retain che abbiamo chiesto di accadere tramite il setter della proprietà sintetizzata.

Di conseguenza, normalmente dichiaro le mie proprietà come questa:

Nell'intestazione:

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

Nel file di implementazione:

@synthesize bla = _bla; 

e poi

_bla = [[SomeClass alloc] init]; 

Pr Ovviamente la mia ipotesi iniziale è corretta - sarei interessato a sapere se c'è un modo "giusto" per farlo, cioè la dichiarazione, l'inizializzazione e la gestione della memoria delle proprietà?

+0

Innanzitutto, benvenuto a Stack Overflow. Una delle cose che è importante fare su Stack è accettare le risposte che funzionano per te. È importante per i rispondenti e per la tua reputazione. – smathy

risposta

8

Sì, hai ragione: l'utilizzo del setter sintetizzato di una proprietà retain aumenterebbe il conteggio di ref in un'istanza che già possiedi (come alloc implica la proprietà).

basta andare con la seconda forma lei ha citato nella vostra inizializzatori:

_bla = [[SomeClass alloc] init]; 

... e ricordatevi di fissare il numero di trattenere altrimenti, per esempio:

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

Penso che questo assegnazione mette il conto di mantenimento per 'bla' in su per due;

Vero.

Sarei interessato a sapere se ci sia modo 'giusto' per fare questo

Il tuo ultimo pezzo di codice è il modo giusto, ma la sottolineatura non è raccomandato. La proprietà e l'ivar possono condividere lo stesso nome. Basta

@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]; 
} 

è sufficiente.


Alcune persone possono utilizzare

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

o

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

nel metodo -init, ma io scoraggiare fortemente, come questo richiede inutilmente molti metodi, and you cannot guarantee the behavior of the setter.

+0

Wao: il mio primo post su StackOverflow e due risposte entro 5 minuti. Grazie ad entrambi! – patschiboy

+6

Nella maggior parte dei casi, i due modelli che scoraggi fortemente sono perfettamente accettabili e normali. La risposta che hai collegato riguarda ** solo ** per l'uso di accessori per impostare oggetti nei metodi 'init' e' dealloc'. Ovunque, la raccomandazione di Apple è sempre quella di utilizzare gli accessor per accedere alle variabili di istanza. – JeremyP

+0

JeremyP ha ragione, e per questo motivo questa non dovrebbe essere considerata una risposta corretta. – Felixyz

3

Sembra che il problema principale qui sia un fraintendimento della semantica della proprietà degli oggetti in Cocoa. Per ogni init, copy o retain chiamato su un oggetto, è necessario effettuare una chiamata a release o autorelease. Quello che sta accadendo qui è che la chiamata a init non ha una chiamata corrispondente a release o autorelease.

Penso che la confusione qui sia che la notazione a punti per l'assegnazione di proprietà è zucchero sintattico per una chiamata di metodo. Quindi sembra che sia solo un incarico quando in realtà è una chiamata a un setter di proprietà.

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

non è la stessa cosa:

bla = [[SomeClass alloc] init]; 

L'ex traduce in:

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

mentre il secondo è letteralmente un incarico.

per risolvere il problema tutti si ha realmente bisogno di fare è assicurarsi che il codice che chiama init chiamate autorelease in modo che il conteggio mantenere verrà decrementato dopo la retain chiamata dal setter.

-3

Non c'è un doppio conteggio. Il setter creato da synthesize fa una release prima di fare un retain. Vedi la classe di Stanford sull'obiettivo c classe 3 come indicato nel sito Web di Apple. Vale anche la pena notare che in caso di iboutlet l'allocazione init non è necessaria poiché viene eseguita attraverso il caricamento del file xib

+0

Annotato per aver sbagliato. [[xxx alloc] init] restituisce un oggetto con un numero di ritenzione pari a 1, che deve essere neutralizzato in qualche punto. Se si archivia il risultato in una proprietà mantenuta, quindi si imposta immediatamente la proprietà mantenuta su zero, si verifica una perdita di memoria. – gnasher729

Problemi correlati