É 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)?


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.


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:].


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.