Domanda

Qual è la differenza tra i seguenti 2 modi per allocare e inizializzare un oggetto?

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

e

self.aController= [[AController alloc] init];

La maggior parte dell'esempio di apple usa il primo metodo. Perché dovresti allocare, init e obiettare e quindi rilasciare immediatamente?

È stato utile?

Soluzione

Ogni oggetto ha un conteggio di riferimento. Quando va a 0, l'oggetto viene deallocato.

Supponendo che la proprietà sia stata dichiarata come @property (keep) :

Il tuo primo esempio, riga per riga:

  1. L'oggetto è stato creato da alloc , ha un conteggio di riferimento di 1.
  2. L'oggetto viene passato al metodo self del setAController: , che gli invia un messaggio conserva (perché il metodo non sapere da dove proviene l'oggetto), incrementando il suo conteggio di riferimento a 2.
  3. Il codice chiamante non ha più bisogno dell'oggetto stesso, quindi chiama release , riducendo il conteggio dei riferimenti a 1.

Il tuo secondo esempio sostanzialmente fa i passaggi 1 e 2 ma non 3, quindi alla fine il conteggio dei riferimenti dell'oggetto è 2.

La regola è che se crei un oggetto, sei responsabile di rilasciarlo quando hai finito con esso. Nel tuo esempio, il codice viene eseguito con tempAController dopo aver impostato la proprietà. È responsabilità del metodo setter chiamare trattenere se è necessario che l'oggetto rimanga.

È importante ricordare che self.property = foo; in Objective-C è davvero solo una scorciatoia per [self setProperty: foo]; e che setProperty: il metodo conserverà o copierà gli oggetti secondo necessità.

Se la proprietà fosse stata dichiarata @property (copia) , l'oggetto sarebbe stato copiato anziché conservato. Nel primo esempio, l'oggetto originale sarebbe stato rilasciato immediatamente; nel secondo esempio, il conteggio dei riferimenti dell'oggetto originale sarebbe 1 anche se dovrebbe essere 0. Quindi vorrai comunque scrivere il tuo codice allo stesso modo.

Se la proprietà è stata dichiarata @property (assegnato) , allora self non rivendica la proprietà dell'oggetto e qualcun altro deve mantenerlo. In questo caso, il primo esempio sarebbe errato. Questi tipi di proprietà sono rari, di solito utilizzati solo per i delegati di oggetti.

Altri suggerimenti

Come altri hanno notato, i due frammenti di codice visualizzati non sono equivalenti (per motivi di gestione della memoria). Per quanto riguarda il motivo per cui il primo è scelto rispetto al secondo:

La formulazione corretta di quest'ultimo sarebbe

self.aController= [[[AController alloc] init] autorelease];

Rispetto al primo, questo aggiunge ulteriore sovraccarico attraverso l'uso del pool di autorelease, e in alcune circostanze porterà alla durata dell'oggetto inutilmente estesa (fino al rilascio del pool di autorelease) che aumenterà il footprint di memoria dell'applicazione.

L'altro "possibile" l'implementazione (a seconda della provenienza dell'esempio) è semplicemente:

aController = [[AController alloc] init];

Tuttavia, l'impostazione diretta di una variabile di istanza è fortemente sconsigliata in qualsiasi luogo diverso da un metodo init o dealloc. Altrove dovresti sempre usare i metodi di accesso.

Questo ci porta quindi all'implementazione mostrata nel codice di esempio:

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

Segue le migliori pratiche da:

  • Evita il rilascio automatico;
  • Rende immediatamente chiara la semantica della gestione della memoria;
  • Utilizza un metodo di accesso per impostare la variabile di istanza.

Nota anche che il tuo desiderio di ridurre il codice su una riga è il motivo per cui molte persone usano Autorelease:

self.aController = [[[AController alloc] init] autorelease];

Sebbene in teoria il rilascio automatico dell'iPhone sia in qualche modo più costoso (non ho mai sentito una chiara spiegazione del perché) e quindi potresti voler rilasciare esplicitamente subito dopo aver assegnato l'oggetto altrove.

Se stai usando Xcode, può aiutarti a rilevare tale codice con l'analizzatore statico. Premi Build > > Costruisci e analizza

alt text

Questo ti mostrerà un messaggio molto utile in tali parti di codice.

alt text

Un'altra cosa da notare è che il tuo esempio dipende anche dalla definizione @property di aController.

Se fosse definito come @property (readwrite, keep) id aController; allora il tuo esempio funziona, mentre se è definito come @property (readwrite, assegnato) id aController; quindi la chiamata extra da rilasciare causerebbe la deallocazione dell'oggetto.

Puoi anche farlo

@property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];

con una proprietà di mantenimento, e funzionerebbe allo stesso modo, ma è meglio usare l'altro modo (per conservare le proprietà) perché è meno confuso, quel codice fa sembrare che tu assegni un Controller e quindi viene eliminato dalla memoria , quando in realtà non lo fa perché setAController lo mantiene.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top