2010-02-18 14 views
5

Data la seguente definizione di proprietà:Objective-C Proprietà e gestione della memoria

@property (nonatomic,retain) MyObject* foo; 

ha il seguente codice di causare una perdita di memoria:

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

?

Sembra che la chiamata di alloc incrementi il ​​conteggio di ritenzione sull'oggetto a 1, quindi il mantenimento all'interno del setter di proprietà lo aumenta a 1. Ma poiché il conteggio iniziale non viene mai decrementato a 0, l'oggetto resterà attivo anche quando il sé è rilasciato. Questa analisi è corretta?

Se è così, sembra che io ho due alternative:

self.foo = [[[MyObject alloc] init] autorelease]; 

che non è raccomandato su iPhone per motivi di prestazioni, o:

MyObject* x = [[MyObject alloc] init]; 
self.foo = x 
[x release]; 

che è un po 'ingombrante. Ci sono altre alternative?

risposta

2

Hai ragione, self.foo = [[MyObject alloc] init]; è che perde la memoria. Entrambe le alternative sono corrette e possono essere utilizzate. Per quanto riguarda lo autorelease in una dichiarazione del genere: tenere presente che l'oggetto verrà rilasciato dal pool di autorelease non appena termina il ciclo di esecuzione corrente, ma molto probabilmente verrà trattenuto molto più lungo da self, quindi non vi è alcun problema con l'utilizzo della memoria picchi qui.

3

Esistono alternative?

No.

Non si ha intenzione di essere in grado di scrittura molto più di un'applicazione per iPhone senza utilizzare autorelease e la biblioteca Cocoa Touch li usa in molti luoghi. Comprendi cosa sta facendo (aggiungendo il puntatore a un elenco per la rimozione sul fotogramma successivo) ed evita di utilizzarlo in loop stretti.

È possibile utilizzare il metodo di classe su MyObject che assegna/init/autorelease per pulirlo.

+ (MyObject *)object { 
    return [[[MyObject alloc] init] autorelease]; 
} 

self.foo = [MyObject object]; 
+0

Questa è un'ottima alternativa che consente di risparmiare tempo durante la creazione delle istanze. –

3

Il modo più semplice per gestire una proprietà mantenuto su iPhone è la seguente (autorelease non è così male come si pensa, almeno per la maggior parte degli usi):

-(id)init { 
    if (self = [super init]) { 
     self.someObject = [[[Object alloc] init] autorelease]; 
    } 
    return self; 
} 

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

I autorelease rilascia il riferimento all'istanza mobile assegnata a self.object che conserva il proprio riferimento, lasciandovi l'unico riferimento necessario (someObject). Quindi, quando la classe viene distrutta, viene rilasciato l'unico riferimento rimanente, distruggendo l'oggetto.

Come descritto in un'altra risposta, è anche possibile creare uno o più messaggi di "costruzione" per creare e autorizzare gli oggetti con parametri facoltativi.

+(Object)object; 
+(Object)objectWithCount:(int)count; 
+(Object)objectFromFile:(NSString *)path; 

si potrebbe definire come questi:

// No need to release o if fails because its already autoreleased 
+(Object)objectFromFile:(NSString *)path { 
    Object *o = [[[Object alloc] init] autorelease]; 
    if (![o loadFromFile:path]) { 
     return nil; 
    } 
    return o; 
} 
+0

-1 per non chiamare '[super init]' né '[super dealloc]', che è pericoloso. – MrMage

+0

Errore mio, stavo semplicemente indicando il metodo di assegnazione degli oggetti. Codice aggiornato –

+0

È ancora sbagliato, il metodo di fatto di 'init' implica l'assegnazione del valore di ritorno di' [super init] 'a' self'. – dreamlax