2009-03-20 19 views
6

Esta es una pregunta nivel de principiante en el que estoy ansioso por ver si este es un uso válido de un puntero en una sentencia como:¿Es este un uso válido de un puntero de Objective-C?

NSMutableDictionary *foo = [bar mutableCopy]; 

me confundo cuando eso es válido frente al que había necesidad de haga lo siguiente:

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

¿Ambos son válidos? ¿Cuándo usar uno sobre el otro?

Respuesta

9

Adivinando por qué podría estar confundido, me gustaría agregar una explicación de lo que realmente hace el segundo código (y por qué no es necesario)

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

Creo que se confunde con esta línea porque esta línea a menudo se describe como "inicializar foo". Eso es un poco engañoso. Aquí se modifican técnicamente 2 entidades diferentes: se crea el nuevo objeto NSMutableDictionary y se asigna a la variable "foo" su dirección.

La línea en realidad crea un nuevo objeto NSMutableDictionary en el montón (el área de memoria dinámica de su aplicación). Llamaré a este "Diccionario 1". Para que se pueda encontrar este nuevo objeto "Diccionario 1" en el montón, su dirección de memoria se almacena en "foo". El rol de "foo" es actuar como un índice, por lo que podemos encontrar el "Diccionario 1".

Mientras solemos decir: "foo es un diccionario", eso es porque somos flojos: la afirmación es técnicamente incorrecta. Correctamente: "hay un diccionario en el montón y foo almacena su dirección de memoria para que podamos encontrarlo y usarlo".

Cuando a continuación, ejecuta la línea:

foo = [bar mutableCopy]; 

está utilizando la dirección en la "barra" para encontrar un objeto diferente (lo llamaré "Diccionario 2") en el montón, y hacer aún otro objeto ("Diccionario 3") en el montón con los mismos valores. Si mantienes la cuenta, ahora hay 3 objetos en existencia.

Después de realizar "Diccionario 3", su dirección de memoria se almacena en la variable "foo". Este almacenamiento en "foo" sobrescribe la dirección de memoria existente (la que apuntaba a "Diccionario 1"). Esto significa que no tenemos punteros restantes para "Diccionario 1" y, por lo tanto, nunca podremos encontrarlo nuevamente. Es por eso que decimos que el "Diccionario 1" se ha filtrado.

Espero que pueda ver en esta situación por qué nunca se necesitó el "Diccionario 1" (solo se pretendía usar "foo" para acceder a la copia, "Diccionario 3").

3

La primera es correcta, la segunda pierde la memoria porque usted asigna dos veces (la copia cuenta como una) y la libera solo una vez.

No se olvide de liberar foo después de haber terminado, aunque

+0

No lo suelte. mutableCopy devuelve un objeto liberado automáticamente. – NilObject

+0

de la documentación: el invocador del método, sin embargo, es responsable de liberar el objeto devuelto. – cobbal

+1

@NilObject: No, no es así. Consulte http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmObjectOwnership.html#//apple_ref/doc/uid/20000043-BEHDEDDB –

7

Nunca tendría que escribir el código en el segundo ejemplo. El [[NSMutableDictionary alloc] initWithCapacity:0] no hace nada excepto la memoria de fuga.

En el segundo ejemplo, usted crea un NSMutableDictionary y lo asigna al foo. Luego, en la línea siguiente, asigna una copia de otro NSMutableDictionary al foo, lo que significa que el diccionario original foo señalado ahora está flotando en algún punto del montón, sin poder liberarse.

Necesitará liberar foo en cualquier caso, sin embargo, como se establece en el Objective-C memory management guidelines.

+0

Corrección secundaria: la asignación DESPUÉS de esa línea es la que filtra la memoria. Sin embargo, estoy de acuerdo con usted en que este código nunca debería escribirse. :-) –

1

El acto de asignación sobrescribe el valor anterior mantenido por esa variable. Por ejemplo:

x = 3 
x = 4 

El valor retenido por x en el inicio de la segunda línea es 3, pero después de la línea de código se ejecuta, es 4. La sintaxis:

int x = 0; 

es realmente sólo taquigrafía para esto:

int x; 
x = 0; 

Las variables que son punteros no son diferentes. Por lo tanto, si la primera referencia de la variable es simplemente asignarla, no es necesario inicializarla primero, ya que cualquier valor con el que lo esté inicializando simplemente se descartará.

0

El primero es la forma correcta de hacerlo. Tanto copy como alloc asignarán memoria a su variable. Entonces, usar la segunda opción aumentará el conteo retenido de su variable a 2.