Como funciona o pool de autorelease do NSAutoreleasePool?

Pelo que entendi, qualquer coisa criada com uma alocação , nova ou cópia precisa ser liberada manualmente. Por exemplo:

int main(void) { NSString *string; string = [[NSString alloc] init]; /* use the string */ [string release]; } 

Minha pergunta, porém, não seria tão válida ?:

 int main(void) { NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; NSString *string; string = [[[NSString alloc] init] autorelease]; /* use the string */ [pool drain]; } 

Sim, seu segundo trecho de código é perfeitamente válido.

Toda vez que uma autorização é enviada para um object, ele é adicionado ao pool de autorelease mais interno. Quando o pool é drenado, ele simplesmente envia -release a todos os objects no pool.

Os pools de liberação automática são simplesmente uma conveniência que permite adiar o envio da release até “mais tarde”. Esse “mais tarde” pode acontecer em vários lugares, mas o mais comum nos aplicativos Cocoa GUI é no final do ciclo de ciclo de execução atual.

NSAutoreleasePool: dreno vs. liberação

Como a function de drain e release parece estar causando confusão, pode valer a pena esclarecer aqui (embora isso esteja coberto na documentação …).

Estritamente falando, a partir do drain perspectiva grande figura não é equivalente a release :

Em um ambiente de contagem de referência, o drain executa as mesmas operações que o release , de modo que os dois são equivalentes nesse sentido. Para enfatizar, isso significa que você não vaza um pool se usar o drain vez de release .

Em um ambiente de garbage collection, o release é um não operacional. Assim, não tem efeito. drain , por outro lado, contém uma sugestão para o coletor que deve “coletar se necessário”. Assim, em um ambiente de garbage collection, o uso do drain ajuda o sistema a equilibrar as varreduras de coleta.

Como já foi mencionado, seu segundo trecho de código está correto.

Eu gostaria de sugerir uma maneira mais sucinta de usar o pool de autorelease que funciona em todos os ambientes (ref count, GC, ARC) e também evita a confusão de dreno / liberação:

 int main(void) { @autoreleasepool { NSString *string; string = [[[NSString alloc] init] autorelease]; /* use the string */ } } 

No exemplo acima, observe o bloco @autoreleasepool . Isso está documentado aqui .

Não, você está errado. A documentação declara claramente que em não GC, -drain é equivalente a -release, significando que o NSAutoreleasePool não será vazado.

Eu encontrei este link deu a melhor explicação sobre quando e como usar NSAutoReleasePool: AutoReleasePool

Sim, seu código é perfeito, se você estiver usando garbage collection, seria suficiente apenas definir a seqüência de caracteres para nil quando você é feito com ele. A garbage collection não é boa para o desempenho do seu aplicativo, então eu não recomendaria usá-lo: P

O que eu li da Apple: “No final do bloco do conjunto de autorelease, os objects que receberam uma mensagem de liberação automática no bloco recebem uma mensagem de liberação – um object recebe uma mensagem de liberação para cada vez que foi enviada uma mensagem de liberação automática dentro do bloco. ”

https://developer.apple.com/library/mac/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html

o envio de autorelease em vez de liberação para um object estende a vida útil desse object pelo menos até que o próprio pool seja drenado (pode ser mais longo se o object for posteriormente retido). Um object pode ser colocado no mesmo pool várias vezes, caso em que recebe uma mensagem de liberação para cada vez que foi colocado no pool.

Sim e não. Você acabaria liberando a memory de seqüência de caracteres mas “vazando” o object NSAutoreleasePool para a memory usando dreno em vez de liberar se você executasse isso em um ambiente de lixo coletado (não gerenciado pela memory). Esse “vazamento” simplesmente torna a instância de NSAutoreleasePool “inacessível” como qualquer outro object sem pointers fortes no GC, e o object seria limpo na próxima vez que o GC fosse executado, o que poderia muito bem ser diretamente após a chamada para -drain :

drenar

Em um ambiente de garbage collection, aciona a garbage collection se a memory alocada desde a última coleta for maior que o limite atual; caso contrário, se comporta como liberação. … Em um ambiente de garbage collection, esse método finalmente chama objc_collect_if_needed .

Caso contrário, é semelhante a como -release a -release se comporta em um não GC, sim. Como outros afirmaram, -release não funciona no GC, portanto, a única maneira de garantir que o pool funcione corretamente no GC é através de -drain e -drain em trabalhos que não são do GC exatamente como -release em non-GC, e indiscutivelmente comunica sua funcionalidade mais claramente também.

Devo salientar que a sua declaração “qualquer coisa chamada com novo, alocação ou init” não deve include “init” (mas deve include “copiar”), porque “init” não aloca memory, apenas configura o object (construtor moda). Se você recebesse um object alocado e sua function apenas chamada init, você não o liberaria:

 - (void)func:(NSObject*)allocd_but_not_init { [allocd_but_not_init init]; } 

Isso não consome mais memory do que você já começou (supondo que o init não instancie objects, mas você não é responsável por eles).