Pregunta

Soy nuevo en el código administrado por memoria pero tengo la idea bastante bien.

Al llevar mi aplicación a través de la herramienta de filtraciones en XCode, noté que solo tenía que limpiar mis objetos personalizados, pero no las matrices creadas dinámicamente, por ejemplo, así que pensé que esos tipos de datos se liberan automáticamente, tiene sentido ya que solo tuve que libere las matrices que utilicé como propiedades que tenían un (retener) en ellas.

Entonces noté algo peculiar: me estaba dando una fuga en cierta matriz inicializada así:

NSMutableArray *removals = [NSMutableArray new];

pero no similar

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9];

Ahora, la razón por la que uno se configuró con " new " es que podría tener 0-99 elementos, mientras que el otro que sabía que siempre sería 9. Dado que ambas matrices se pasan al mismo método más tarde en función de la interacción del usuario, recibía una fuga si no lo hacía liberar al final del método, o una excepción si lo hice!

Cambié la primera matriz a

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

y no tengo fugas y no tengo que liberar nada. ¿Alguien puede explicar?

¿Fue útil?

Solución

Como se indica en las reglas de administración de memoria , siempre que tenga un objeto que haya creado con + alloc , + new , -copy o -mutableCopy , usted es el propietario y es responsable de liberarlo en algún momento. (De hecho, + new es solo una forma abreviada de [[MyClass alloc] init] .) Como notó, crear una matriz a través de [NSArray new] sin liberarlo es una pérdida de memoria. Sin embargo, si maneja este objeto correctamente, generalmente es posible liberarlo en algún momento. Por ejemplo:

  • Si el método que usa la matriz se llama desde dentro de el método que crea la matriz, entonces debería poder liberar la matriz después de que haya ha sido usado. Si el método interno necesita mantener una referencia más permanente a la matriz, entonces ese método es responsable de enviar -retain y, eventualmente, -release al objeto. Por ejemplo:

    - (void)myMethod {
        NSArray *removals = [NSArray new];
        // ...
        [someObject someOtherMethod:removals];
        [removals release];
    }
    
  • Si creó la matriz en un método -init para un objeto, entonces el método -dealloc puede liberarlo cuando se destruye el objeto.

  • Si necesita crear la matriz y luego devolverla del método, ha descubierto la razón por la cual se inventó el alquiler automático. La persona que llama de su método no es responsable de liberar el objeto, ya que no es un + alloc , + new , -copy , o el método -mutableCopy , pero debe asegurarse de que finalmente se lance. En este caso, llama manualmente a -autorelease en el objeto antes de devolverlo. Por ejemplo:

    - (NSArray *)myMethod {
        NSArray *removals = [NSArray new];
        // ...
        return [removals autorelease];
    }
    

Cuando crea la matriz a través de + arrayWithCapacity: , no está llamando a uno de los " especiales " métodos, para que no tenga que publicar el resultado. Esto probablemente se implementa con -autorelease , muy parecido al último ejemplo anterior, pero no necesariamente. (Por cierto, también puede crear un NSMutableArray vacío publicado automáticamente con [NSMutableArray array] ; el método se encuentra en NSArray, por lo que no aparecerá en la documentación bajo NSMutableArray, pero creará un mutable matriz cuando se envía a la clase NSMutableArray.) Si va a devolver la matriz de su método, puede usar esto como abreviatura para [[[NSMutableArray alloc] init] autorelease] & # 8212 ; pero es solo un atajo. Sin embargo, en muchas situaciones, puede crear un objeto con -init o + new y liberarlo manualmente en el momento apropiado.

Otros consejos

Así es como se implementaron las cosas detrás de escena:

+(NSMutableArray*) new
{
    return [[NSMutableArray alloc] init];
}

y

+(NSMutableArray*) arrayWithCapacity:(NSNumber)capacity
{
    return [[NSMutableArray alloc] initWithCapacity:capacity] **autorelease**];
}

En el primer caso, la matriz se asigna solo y usted es responsable de desasignarla. Por el contrario, arrayWithCapacity se ha lanzado automáticamente para usted y no causará fugas, incluso si olvida desasignar.

Cocoa usa ciertas convenciones de nomenclatura. Cualquier cosa que comience con alloc, new o copy devuelve algo con un Retención de Conteo de 1 y se le exige que la libere. Cualquier otra cosa que devuelva una función tiene un contenido de retención equilibrado (podría ser retenido por otra cosa o retenido y liberado).

Entonces:

NSMutableArray *removals = [NSMutableArray new];

Tiene un RetenCount de 1 y:

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

o

NSMutableArray *removals = [NSMutableArray array];

No, ya que los métodos no tienen el prefijo alloc, new o copy Todo esto se explica en la gestión de memoria documentación . En particular:

  

Usted toma posesión de un objeto si   crearlo usando un método cuyo nombre   comienza con & # 8220; alloc & # 8221; o & # 8220; nuevo & # 8221; o   contiene & # 8220; copia & # 8221; (por ejemplo, alloc,   newObject o mutableCopy), o si   envíele un mensaje de retención. Usted está   responsable de renunciar   propiedad de los objetos que posee   lanzamiento o autorelease. En otro momento   recibes un objeto, no debes   libérelo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top