2010-06-28 23 views
5

Soy un novato de iPhone/Objective-C con un extenso fondo Java.NSMutableArray arrayWithCapacity vs initWithCapacity

estoy aprendiendo más sobre la gestión de memoria en Objective-C y estoy leyendo la documentación de Apple sobre la gestión de la memoria: http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

En la sección de Política de la propiedad de objetos, se dice que es el propietario de cualquier objeto creado a través de una método que comienza con alloc, new o contains copy. La propiedad implica que necesita explícitamente release el objeto cuando haya terminado con él.

lo que estoy buscando en la documentación NSMutableArray: http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html

Hay dos métodos que más o menos hacen lo mismo ... que ambos crean una matriz con una cierta capacidad inicial. Uno es un método de clase y el otro es un método de instancia.

+ (id)arrayWithCapacity:(NSUInteger)numItems; 
- (id)initWithCapacity:(NSUInteger)numItems; 

Ahora es el perezoso desarrollador de Java que soy, ¿por qué alguna vez elegir el método de instancia sobre el método de clase sabiendo que en algún momento en el tiempo que tengo que limpiar después de mí?

Supongo que me puede estar faltando un punto fundamental aquí ... ¿es simplemente cuestión de determinar cuando se libera el objeto? autorelease en el método de clase vs. release en el método de instancia? Supongo que en una plataforma con recursos muy limitados (iPhone) debo abstenerme de utilizar el método de clase y liberar el objeto tan pronto como haya terminado con él.

Gracias!

Respuesta

9

Por lo general, elegirá en función de si va a ser propietario del objeto durante más tiempo que el método actual (por ejemplo, asignarlo a un elemento estático o directamente a un ivar). En ese caso, puede usar el método alloc/init ya que sabe que ya lo quiere. Si planea usarlo solo para el alcance del método actual, o lo está asignando a algo administrado como una propiedad, entonces probablemente use el método de conveniencia.

Cuando sabe que va a ser propietario de un objeto que está creando, la llamada alloc/init es siempre más eficiente que la conveniencia/retención ya que este último es necesario para básicamente alloc/init/autorrelease el objeto y luego lo conservas cuando es devuelto.

También puede utilizar los métodos alloc/init directos cuando está asignando un bucle y no necesita/desea tratar con un grupo de autorrelease.

+0

¿Es esto cierto más ahora que tenemos recuento automático de referencias? Me parece que los dos métodos deben ser bastante idénticos ahora, ya que el código ARC básicamente aplica una liberación automática implícita al objeto alloc/init creado ahora. Se vería que en la mayoría de los casos deberíamos usar los métodos de conveniencia ahora si esto existe por simplicidad y claridad, ya que no hay ninguna penalización de rendimiento para nadie, si entiendo esto correctamente. – Mike

0

En este caso, yo trate de cumplir con las siguientes reglas para evitar la memoria relacionada con la (== "muy desagradable") errores:

  • si estás de paso esa matriz como un parámetro, entonces se puede utilizar la método de fábrica sin ningún problema, ya que es la responsabilidad de la función de aceptar para retener/liberarlo
  • si desea seguir trabajando con el objeto, utilice el método de inicialización y liberar el objeto al final
6

arrayWithCapacity: ya tiene la autorrelease aplicada.

initWithCapacity: se conserva explícitamente y tendrá que liberarlo usted mismo. Como lo llamas usualmente como [[A alloc] init ...], esto disparará una bombilla "Necesito administrar la memoria para esto", otras palabras mágicas similares además de "alloc" son "nuevas" y "copian" mientras lee en la guía de administración de memoria. Pero a partir de su pregunta, parece que comprende bien los principios de la misma.

Tiene razón en que debe mantener la huella de memoria bajo y administrada, pero esto no significa que deba hacer siempre una apertura/inicio explícito. Como dice Nick, un caso de uso para usar métodos de fábrica de liberación automática es cuando los pasas como parámetros.

Otro ejemplo es que cuando agrega algo a una colección como NSDictionary o NSArray, ese "algo" se puede crear con el método de fábrica de liberación automática, ya que la colección "asume" retenerlo. (Las cosas se conservan cuando se añade a la colección, y se liberan cuando se retiran.)

Se puede argumentar que

Blah *blah = [Blah blahWithSomething]; 
[myMutableArray addObject:blah]; 

es sólo más limpio que escribir que

Blah *blah = [[Blah alloc] initWithSomething]; 
[myMutableArray addObject:blah]; 
[blah release]; 

En el primer caso, lo hace no necesita preocuparse por una llamada de liberación en absoluto. La desventaja es que cuando haces esto muchas veces en el mismo runloop, la huella de memoria del primer caso es mayor SI es un objeto de matriz temporal/desechable que desaparece al final del runloop. Pero si se trata de un objeto pequeño que no se realiza en un bucle y se retiene durante más tiempo como es un caso común, sus huellas son las mismas.