2011-09-29 9 views
14

Si tengo un NSMutableArray de objetos personalizados, ¿cómo puedo borrar fácilmente la matriz sin causar ningún problema de memoria? Supongamos que la clase de objeto personalizada tiene un método dealloc que libera correctamente una variable de instancia, etc.cómo borrar un NSMutableArray de objetos personalizados sin crear pérdidas de memoria?

Por ejemplo, ¿está bien utilizar el método NSArray "removeAllObjects"?

  • Si es así - ¿cómo funciona esto - no "removeAllObjects" llamar al método "dealloc" en cada objeto, ya que les quita

  • Si no - lo que sería el enfoque más fácil de usar?

EDITAR (después de 4 respuestas) - Una última pregunta de aclaración después de las grandes respuestas - Todavía no estoy muy seguro acerca de la instancia variables/propiedades en mi objeto personalizado que os he puesto para retener? Estos parecen ser lanzados solo a través del método "dealloc" en mi clase de objeto personalizado, donde lo hacemos manualmente junto con [superlanzamiento].

Entonces, si borrar una matriz, si hago una removeAllObjects, y luego NSArray emite una "versión" a mis objetos personalizados, pero no llama a "dealloc", ¿cómo se liberan mis variables de instancia?

+1

Nadie debe llamar 'dealloc' que no sea el administrador de memoria (o' dealloc' de una subclase). 'removeAllObjects' llama a' release' en cada objeto, ya que lo borra de la matriz. –

+2

sí, si ve un 'dealloc' en su código que no es parte de' [super dealloc]; 'lo está haciendo mal. –

Respuesta

31

removeAllObjects eliminará el objeto a partir de la matriz. Este proceso enviará un mensaje de liberación al objeto y esto disminuirá su recuento de referencia. Cuando el recuento de referencia llega a cero, el objeto será desasignado.

no lo hagas así porque se perderá.

NSObject *object = [[NSObject alloc] init];  + 1 
[array addObject:object];       + 1 
[array removeAllObjects];       - 1 
               ======= 
               = + 1 -> Leak 

esta es la forma correcta:

NSObject *object = [[[NSObject alloc] init] autorelease]; + 1 (from alloc) - 1 (from autorelease) 
[array addObject:object];       + 1 
[array removeAllObjects];       - 1 
               ======= 
               = 0 -> Object will be deallocated 

En lugar de removeAllObjects que le llama simplemente podría liberar la matriz. Si se desasigna una matriz, se libera todo lo que está dentro de ella y, si no hay otra referencia al objeto, se desasignará.

+0

gracias - acabo de agregar una pregunta de aclaración como una EDITACIÓN en mi pregunta si está bien ... – Greg

+0

disculpe mi respuesta tardía, pero una vez que el recuento de referencias llega a cero, el sistema llamará a dealloc sobre el objeto. No tienes que hacer esto. –

+5

Al usar ARC, esta situación es manejada correctamente por el sistema de primera manera, ¿no es así? – Alex

3

Sí, sólo llame removeAllObjects. Solo para estar seguro, no llama al retain cuando agrega un objeto a una matriz o cuando crea una matriz con objetos. Eso está hecho para ti automáticamente.

En cuanto dealloc, una vez más que se llevará a cabo de forma automática, y no se puede predecir cuándo.

La única cosa que hay que tener en el dealloc es el propio objeto de matriz. Es decir, ¿suponiendo que sea una variable de instancia o ivar?

para comprobar que todo está bien, ejecute el producto utilizando el Analizador -> Analizar. Y luego déle un perfil a la aplicación en Instruments usando el instrumento Leaks para verificar que ninguno de su código esté causando pérdidas de memoria.

1

El método dealloc nunca es llamado directamente. Todo se hace a través del mecanismo retain/release (y el principio de recuento de referencias). Así que este es el método release que se llama, no el dealloc directamente.El método de ejecución dealloc solo es invocado por el motor de ejecución si la última llamada release hace que el recuento de referencias (retainCount) del objeto llegue a cero, lo que significa que el objeto realmente se desasigna de la memoria ya que nadie lo usa.

NSArray y todas las clases de contenedores en Cocoa (NSDictionary, NSSet, ...) conservan sus valores. Entonces, cuando agrega un objeto a un contenedor como NSArray, será retain ese valor. Y cuando se quita ese valor (incluyendo cuando se llama removeAllObjects ") se release que

reglas Mgmt memoria son fáciles de seguir:., Pero la única regla que importa es que usted sólo tiene que llamar release o autorelease si se llama alloc, retain o copy métodos. Eso es siempre la responsabilidad del objet el que hizo la alloc/retain/copy a llamar a la release/autorelease. Nunca deje a un alloc/retain/copy sin espera de llamada release/autorelease para equilibrarlo (o usted tendrá fugas), pero por otro lado nunca llame al release/autorelease si no hizo la llamada alloc/retain/copy.

Buena ejemplo 1:

MyClass* obj = [[MyClass alloc] init]; // here you do an alloc 
[myArray addObject:obj]; // the NSArray "myArray" retains the object obj 
// so now you can release it, the array has the responsability of the object while it is held in the array 
[obj release]; // this release balance the "alloc" on the first line, so that's good 

[myArray removeAllObjects]; // there the object held by the array receive a release while being removed from the array. As nobody retains it anymore, its dealloc method will be called automatically. 

Buena ejemplo 2:

MyClass* obj = [[MyClass alloc] init]; // here you do an alloc 
[myArray addObject:obj]; // the NSArray "myArray" retains the object obj 
// so now you can release it, the array has the responsability of the object while it is held in the array 
[myArray removeAllObjects]; // there the object held by the array receive a release while being removed from the array. But your own code still retains a reference to it (because of the "alloc" on first line) so it won't be removed from memory right now 
[obj release]; // this release balance the "alloc" on the first line, and as nobody retains the object anymore, its dealloc method will be called and it will be deallocated from memory 

Buena ejemplo 3:

MyClass* obj = [self getSomeObjectFromAnotherMethod]; // here you don't have an "alloc" on this line 
[myArray addObject:obj]; // the array retains the object 
[myArray removeAllObjects]; // the array release the object while it removes it from the array 
// no need to call "release" here as there is no "alloc" done in the scope of this code 

Mal ejemplo:

MyClass* obj = [self getSomeObjectFromAnotherMethod]; // here you don't have an "alloc" on this line 
[myArray addObject:obj]; // the array retains the object 
[myArray removeAllObjects]; // the array release the object while it removes it from the array 
[obj release]; // Crash here! obj does not exists anymore and has been deallocated from memory before this line! 
+0

gracias - acabo de agregar una pregunta de aclaración como una EDITACIÓN en mi pregunta si está bien ... – Greg

1

Básicamente removeAllObjects método envía release mensaje a todos los objetos. El versión método disminuye la cuenta de referencia de los objetos. Y si el recuento de referencias de un objeto alcanza el 0, se enviará el mensaje dealloc al objeto.

La respuesta a su pregunta es llamando al [array removeAllObjects] es completamente seguro. Por cierto, si ya no quiere la matriz, puede llamar directamente al [array release], que libera todos sus objetos y la matriz.

+0

Usted dice que envía un método de liberación ipso facto. ¿Eso es por ARC? –

Cuestiones relacionadas