É necessário usar autoreleasepool em um programa Swift?

95

Na página 17 desta apresentação WWDC14 , diz

Trabalhando com Objective-C? Ainda preciso gerenciar pools de
liberação automática autoreleasepool {/ * code * /}

O que isso significa? Isso significa que, se minha base de código não tiver nenhum arquivo Objective-C, autoreleasepool {}é desnecessário?

Em uma resposta a uma pergunta relacionada , há um exemplo em que autoreleasepoolpode ser útil:

- (void)useALoadOfNumbers {
    for (int j = 0; j < 10000; ++j) {
        @autoreleasepool {
            for (int i = 0; i < 10000; ++i) {
                NSNumber *number = [NSNumber numberWithInt:(i+j)];
                NSLog(@"number = %p", number);
            }
        }
    }
}

Se o código acima for traduzido para o Swift com autoreleasepooleliminado, o Swift será inteligente o suficiente para saber que a numbervariável deve ser lançada após o primeiro }(como fazem algumas outras linguagens)?

Ethan
fonte
1
Parece não haver documentação autoreleasepoolno Swift. I expandiu sua pergunta e pediu-lo nos fóruns dev .
Aaron Brager de

Respostas:

197

O autoreleasepoolpadrão é usado em Swift ao retornar autoreleaseobjetos (criados por seu código Objective-C ou usando classes Cocoa). O autoreleasepadrão em Swift funciona da mesma forma que em Objective-C. Por exemplo, considere esta versão em Swift do seu método (instanciar NSImage/ UIImageobjetos):

func useManyImages() {
    let filename = pathForResourceInBundle

    for _ in 0 ..< 5 {
        autoreleasepool {
            for _ in 0 ..< 1000 {
                let image = NSImage(contentsOfFile: filename)
            }
        }
    }
}

Se você executar isso em instrumentos, verá um gráfico de alocações como o seguinte:

com autoreleasepool

Mas se você fizer isso sem o pool de liberação automática, verá que o pico de uso de memória é maior:

sem autoreleasepool

O autoreleasepoolpermite que você gerencie explicitamente quando os objetos de liberação automática são desalocados no Swift, assim como você fazia em Objective-C.

Nota: Ao lidar com objetos nativos Swift, você geralmente não receberá objetos de liberação automática. É por isso que a apresentação mencionou a ressalva sobre a necessidade disso apenas ao "trabalhar com Objective-C", embora eu gostaria que a Apple fosse mais clara neste ponto. Mas se você estiver lidando com objetos Objective-C (incluindo classes Cocoa), eles podem ser objetos de liberação automática, caso em que esta versão do Swift do @autoreleasepoolpadrão Objective-C ainda é útil.

Roubar
fonte
2
Em todas estas perguntas, você pode escrever sua própria classe, e tê-lo fazer um printlnno deinit, e torna-se bastante fácil de verificar precisamente quando os objetos são desalocados. Ou observe em Instrumentos. Em resposta à sua pergunta, parece que os objetos Swift são retornados de funções com contagem de retenção +1 (não objetos de liberação automática), e o chamador irá gerenciar perfeitamente a propriedade a partir desse ponto (por exemplo, se e quando o objeto retornado sair do escopo, ele é imediatamente desalocado, não colocado em um pool de liberação automática).
Rob
3
@StevenHernandez Um pool de liberação automática tem muito pouco a ver com vazamentos. Um vazamento é causado por um objeto não liberado. O pool de liberação automática, por outro lado, é apenas uma coleção de objetos para os quais a liberação é adiada até que o pool seja drenado. Os pools não controlam se algo é desalocado ou não, mas apenas o momento dessa desalocação. Remapear a visualização, você não pode controlar o que o cache faz (usa memória, mas não o vazamento verdadeiro) nem fazer nada se houve um vazamento real (e eu não estou ciente de nenhum vazamento significativo na visualização do mapa, embora historicamente tenha havido vazamentos modestos e aleatórios no UIKit).
Rob
2
@matt Sim, vi um comportamento semelhante. Então, repeti meu exercício com NSImage/ UIImageobjects e manifestei o problema de forma mais consistente (e, francamente, este é um exemplo mais comum do problema, já que o pico de uso de memória muitas vezes só é problemático ao lidar com objetos maiores; um exemplo prático disso pode ser uma rotina de redimensionamento de um monte de imagens). Também reproduzi o comportamento chamando o código Objective-C que criava explicitamente objetos de autorelease. Não me interpretem mal: acho que precisamos de pools de liberação automática em Swift com menos frequência do que em Objective-C, mas ainda tem um papel a cumprir.
Rob
1
Encontrei um exemplo que funciona! Basta ligar para o NSBundle pathForResource:ofType:repetidamente.
domingo
1
Meu pathForResource:ofType:exemplo não funciona mais no Xcode 6.3 / Swift 1.2. :)
matt
4

Se você o usasse no código Objective-C equivalente, você o usaria no Swift.

o Swift será inteligente o suficiente para saber que a variável numérica deve ser lançada após o primeiro?

Somente se Objective-C o fizer. Ambos operam de acordo com as regras de gerenciamento de memória Cocoa.

É claro que o ARC sabe que numbersai do escopo no final daquela iteração do loop e, se o reteve, o liberará lá. No entanto, isso não informa se o objeto foi liberado automaticamente, porque -[NSNumber numberWithInt:] pode ou não ter retornado uma instância liberada automaticamente. Não há como saber, porque você não tem acesso à fonte de -[NSNumber numberWithInt:].

newacct
fonte
1
Se Swift se comporta da mesma forma que Objective-C para isso, por que a apresentação mencionou "Trabalhando com Objective-C?" especificamente?
Ethan
9
@Ethan Parece que os objetos Swift nativos não são objetos de liberação automática, e a autoreleasepoolconstrução é totalmente desnecessária. Mas se seu código Swift está lidando com objetos Objective-C (incluindo objetos Cocoa), eles seguem padrões de autorelease e, portanto, a autoreleasepoolconstrução se torna útil.
Rob
Eu entendo que "O autoreleasepool permite que você gerencie explicitamente quando os objetos de autorelease são desalocados no Swift", mas por que eu iria querer? Por que o compilador não faz / não pode fazer isso por mim? Tive que adicionar meu próprio autoreleasepool para evitar que o VM subisse pelo telhado em um loop apertado de enormes manipulações de cordas. Era óbvio para mim onde deveria ser adicionado e funcionou perfeitamente. Por que o compilador não conseguiu fazer isso? O compilador poderia ser mais inteligente para fazer um bom trabalho?
vonlost