2009-03-20 14 views
6

Questa è una domanda livello principiante in cui io sono curioso di sapere se si tratta di un uso valida di un puntatore in una dichiarazione come:È un uso valido di un puntatore Objective-C?

NSMutableDictionary *foo = [bar mutableCopy]; 

mi confondo quando cioè valida rispetto a quando avevo bisogno di effettuare le seguenti operazioni:

NSMutableDictionary *foo = [[NSMutableDictionary alloc] initWithCapacity:0]; 
foo = [bar mutableCopy]; 
// use foo 
[foo release]; 

Sono entrambi validi? Quando usarne uno sull'altro?

risposta

9

Indovinando il motivo per cui potresti essere confuso, vorrei aggiungere una spiegazione di ciò che effettivamente fa il secondo codice (e perché non è necessario).

NSMutableDictionary *foo = [[NSMutableDictionary alloc] initWithCapacity:0]; 

Penso che si sta ottenendo confuso da questa linea, perché questa linea è spesso descritto come "foo inizializzazione". Questo è un po 'fuorviante. Ci sono tecnicamente 2 entità diverse che vengono modificate qui: il nuovo oggetto NSMutableDictionary viene creato e alla variabile "foo" viene assegnato il suo indirizzo.

La linea crea effettivamente un nuovo oggetto NSMutableDictionary nello heap (area di memoria dinamica dell'applicazione). Chiamerò questo "Dizionario 1". In modo che questo nuovo oggetto "Dizionario 1" sull'heap possa essere trovato, il suo indirizzo di memoria è memorizzato in "pippo". Il ruolo di "foo" è quello di agire come un indice, quindi possiamo trovare "Dizionario 1".

Mentre spesso diciamo: "foo is a dictionary", perché siamo pigri, l'affermazione è tecnicamente sbagliata. Correttamente: "c'è un dizionario sull'heap e foo memorizza il suo indirizzo di memoria in modo che possiamo trovarlo e usarlo".

Quando si esegue quindi la linea:

foo = [bar mutableCopy]; 

si sta utilizzando l'indirizzo in "bar" per trovare un oggetto diverso (lo chiamerò "Dizionario 2") nel mucchio, e fare ancora un un altro oggetto ("Dizionario 3") sull'heap con gli stessi valori. Se stai mantenendo il conto, questo è ora 3 oggetti esistenti.

Dopo aver creato "Dizionario 3", il suo indirizzo di memoria viene quindi memorizzato nella variabile "foo". Questa memorizzazione in "pippo" sovrascrive l'indirizzo di memoria esistente (quello che indicava "Dizionario 1"). Ciò significa che non abbiamo puntatori rimanenti per "Dizionario 1" e quindi non sarà mai in grado di trovarlo di nuovo. Questo è il motivo per cui diciamo che "Dizionario 1" è trapelato.

Spero che tu possa vedere da questa situazione perché "Dizionario 1" non è mai stato necessario (hai sempre pensato di utilizzare "foo" per accedere alla copia, "Dizionario 3").

3

Il primo è corretto, il secondo interrompe la memoria perché si assegna due volte (la copia conta come uno) e viene rilasciata una sola volta.

Non dimenticare di rilasciare foo dopo che si è fatto però

+0

Non rilasciarlo. mutableCopy restituisce un oggetto autoreleased. – NilObject

+0

dalla documentazione: l'invocatore del metodo, tuttavia, è responsabile del rilascio dell'oggetto restituito. – cobbal

+1

@NilObject: No, non è così. Vedi http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmObjectOwnership.html#//apple_ref/doc/uid/20000043-BEHDEDDB –

7

Si sarebbe mai bisogno di scrivere il codice nel secondo esempio. Lo [[NSMutableDictionary alloc] initWithCapacity:0] non fa nulla tranne la perdita di memoria.

Nel secondo esempio, si crea un NSMutableDictionary e lo si assegna a foo. Quindi nella riga successiva, si assegna una copia di un altro NSMutableDictionary a foo, il che significa che il dizionario originale foo a cui punta ora sta semplicemente fluttuando da qualche parte nell'heap, incapace di essere mai liberato.

In entrambi i casi sarà necessario rilasciare foo come previsto nello Objective-C memory management guidelines.

+0

Correzione minima: l'assegnazione DOPO quella linea è ciò che perde la memoria. Tuttavia, sono d'accordo con te che questo codice non dovrebbe mai essere scritto. :-) –

1

L'atto di assegnazione sovrascrive il valore precedente detenuto da tale variabile. Ad esempio:

x = 3 
x = 4 

Il valore contenuto x all'inizio della seconda linea è 3, ma dopo la riga di codice esegue, è 4. La sintassi:

int x = 0; 

è in realtà solo stenografia per questo:

int x; 
x = 0; 

Le variabili che sono puntatori non sono diverse. Quindi, se il primo riferimento della variabile è semplicemente assegnarlo, non è necessario inizializzarlo, perché qualsiasi valore con cui lo si sta inizializzando verrà semplicemente scartato.

0

Il primo è il modo giusto per farlo. Sia la copia che l'allocazione assegneranno memoria alla variabile. Quindi, utilizzando la seconda opzione aumenterà il conteggio di mantenimento della variabile a 2.

Problemi correlati