Pergunta

Eu sou novo para código gerenciado memória mas tenho a ideia muito bem.

Ao assumir meu aplicativo através da ferramenta de vazamentos no XCode, eu notei que eu só tinha que limpar meus objetos personalizados, mas não criadas dinamicamente matrizes por exemplo, então achei esses tipos de dados são autoreleased - faz sentido desde que eu só tinha que liberar as matrizes que eu usei como propriedades que tinham um (manter) sobre eles.

Então notei algo peculiar: Eu estava ficando um vazamento em um determinado conjunto inicializada assim:

NSMutableArray *removals = [NSMutableArray new];

, mas não um similar

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:9];

Agora, a única razão foi criada com "novo" é que ele poderia ter 0-99 itens nele, enquanto o outro eu sabia que ia ser sempre 9. Desde ambas as matrizes são passados ??para o mesmo método mais tarde com base na interação do usuário, ou eu estava ficando um vazamento se eu não liberar no final do método, ou uma exceção se eu fiz!

Eu mudei a primeira matriz para

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

e eu fico sem vazamentos e não têm para liberar qualquer coisa. Alguém pode explicar?

Foi útil?

Solução

Como observado nas regras de gerenciamento de memória do , sempre que você tem um objeto que você criou com +alloc, +new, -copy, ou -mutableCopy, que ele próprio e são responsáveis ??por liberá-lo em algum ponto. (Na verdade, +new é apenas uma abreviação para [[MyClass alloc] init].) Como você observou, criando uma matriz via [NSArray new] sem liberá-lo é um vazamento de memória. No entanto, se você lidar com este objeto corretamente, geralmente é possível para liberá-lo em algum ponto. Por exemplo:

  • Se o método que usos a matriz é chamado de dentro o método que cria a matriz, então você deve ser capaz de liberar a matriz depois que ele tem sido usado. Se o método interno precisa manter uma referência mais permanente para a matriz ao redor, em seguida, esse método é responsável por enviar -retain e, finalmente, -release ao objeto. Por exemplo:

    - (void)myMethod {
        NSArray *removals = [NSArray new];
        // ...
        [someObject someOtherMethod:removals];
        [removals release];
    }
    
  • Se você criou a matriz em um método -init para um objeto, então o método -dealloc pode liberá-lo quando o objeto é destruído.

  • Se você precisa para criar a matriz e, em seguida, retorno -lo a partir do método, você descobriu a razão que autoreleasing foi inventado. O chamador do seu método não é responsável por liberar o objeto, uma vez que não é uma +alloc, +new, -copy, ou método -mutableCopy, mas você precisa garantir que ele seja liberado eventualmente. Neste caso, você chamar manualmente -autorelease no objeto antes de devolvê-lo. Por exemplo:

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

Quando você criar a matriz via +arrayWithCapacity:, você não está chamando um dos métodos "especiais", para que você não tem que liberar o resultado. Isso provavelmente é implementado com -autorelease, muito parecido com o último exemplo acima, mas não necessariamente. (Aliás, você também pode criar um NSMutableArray autoreleased vazio com [NSMutableArray array]; o método é encontrado em NSArray, por isso não vai aparecer na documentação sob NSMutableArray, mas vai criar uma matriz mutável quando enviadas para a classe NSMutableArray). Se você vai voltar a matriz de seu método, você pode usar isso como uma abreviação para [[[NSMutableArray alloc] init] autorelease]-mas é apenas um atalho. Em muitas situações, no entanto, você pode criar um objeto com -init ou +new manualmente e lançá-lo no momento apropriado.

Outras dicas

Esta é a forma como as coisas implementadas por trás da cena:

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

e

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

No primeiro caso, a matriz é alocada e só você é responsável por de alocar-lo. Ao contrário do arrayWithCapacity tem autoreleased para você e não irá causar vazamento, mesmo que você se esqueça de desalocar.

Cocoa utiliza certas convenções de nomenclatura. Qualquer coisa que começa com alloc, novos ou copiar retornos algo com um retainCount de 1 e você é obrigado a liberar. Qualquer outra coisa que a função retorna tem um retainCount equilibrado (pode ser realizada por outra coisa, ou pode ser retido e fora liberado).

Assim:

NSMutableArray *removals = [NSMutableArray new];

Tem uma retainCount de 1, e:

NSMutableArray *removals = [NSMutableArray arrayWithCapacity:99];

ou

NSMutableArray *removals = [NSMutableArray array];

Do not já que os métodos não são prefixados com alloc, novo ou copiar. Isso tudo é explicitada no gerenciamento de memória documentação . Em particular:

Você se apropriar de um objeto se você criá-lo usando um método cujo nome começa com “alloc” ou “novo” ou contém “copiar” (por exemplo, alloc, newObject, ou mutableCopy), ou se você enviá-lo a manter a mensagem. Tu es responsável por abrir mão a propriedade de objetos você possui usando liberar ou autorelease. Qualquer outra vez você recebe um objeto, você não deve liberá-lo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top