Est-il nécessaire d'utiliser autoreleasepool dans un programme Swift?

95

À la page 17 de cette présentation de la WWDC14 , il est dit

Travailler avec Objective-C? Vous devez encore gérer les pools de
libération automatique autoreleasepool {/ * code * /}

Qu'est-ce que ça veut dire? Cela signifie-t-il que si ma base de code ne contient aucun fichier Objective-C, autoreleasepool {}est-ce inutile?

Dans une réponse à une question connexe , il y a un exemple où cela autoreleasepoolpeut être utile:

- (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);
            }
        }
    }
}

Si le code ci-dessus est traduit en Swift avec autoreleasepooldrop, Swift sera-t-il assez intelligent pour savoir que la numbervariable doit être publiée après la première }(comme le font d'autres langues)?

Ethan
la source
1
Il ne semble y avoir aucune documentation sur autoreleasepoolSwift. J'ai développé votre question et l' ai posée dans les forums de développement .
Aaron Brager

Réponses:

197

Le autoreleasepoolmodèle est utilisé dans Swift lors du retour des autoreleaseobjets (créés par votre code Objective-C ou à l'aide de classes Cocoa). Le autoreleasemodèle dans Swift fonctionne un peu comme il le fait dans Objective-C. Par exemple, considérez ce rendu Swift de votre méthode (instanciation NSImage/ UIImageobjets):

func useManyImages() {
    let filename = pathForResourceInBundle

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

Si vous exécutez ceci dans Instruments, vous verrez un graphique d'allocations comme celui-ci:

avec autoreleasepool

Mais si vous le faites sans le pool de libération automatique, vous verrez que l'utilisation maximale de la mémoire est plus élevée:

sans autoreleasepool

Le autoreleasepoolvous permet de gérer explicitement le moment où les objets de libération automatique sont désalloués dans Swift, tout comme vous avez pu le faire dans Objective-C.

Remarque: lorsque vous traitez avec des objets natifs Swift, vous ne recevrez généralement pas d'objets à libération automatique. C'est pourquoi la présentation a mentionné la mise en garde sur le fait de n'avoir besoin de cela que lorsque "travailler avec Objective-C", bien que j'aurais aimé qu'Apple soit plus clair sur ce point. Mais si vous avez affaire à des objets Objective-C (y compris des classes Cocoa), ils peuvent être des objets à libération automatique, auquel cas ce rendu Swift du @autoreleasepoolmodèle Objective-C est toujours utile.

Rob
la source
2
Sur toutes ces questions, vous pouvez écrire votre propre classe et lui faire faire un printlnin deinit, et il devient assez facile de vérifier précisément quand les objets sont désalloués. Ou observez-le dans Instruments. En réponse à votre question, il semble que les objets Swift soient renvoyés à partir de fonctions avec un compte de conservation +1 (pas d'objets de libération automatique), et l'appelant gérera de manière transparente la propriété à partir de ce point (par exemple, si et quand l'objet retourné tombe hors de portée, il est immédiatement désalloué et non placé dans un autoreleasepool).
Rob du
3
@StevenHernandez Une piscine autorelease a très peu à voir avec les fuites. Une fuite est causée par un objet inédit. Le pool Autorelease, quant à lui, n'est qu'un ensemble d'objets dont la libération est différée jusqu'à ce que le pool soit vidé. Les pools ne contrôlent pas si quelque chose est désalloué ou non, mais plutôt simplement le moment de cette désallocation. En ce qui concerne la vue de la carte, vous ne pouvez pas contrôler ce que fait la mise en cache (utilise la mémoire, mais pas la vraie fuite) ni faire quoi que ce soit s'il y avait une vraie fuite (et je ne suis pas au courant de fuites importantes de la vue de la carte, bien qu'historiquement il y en ait eu fuites aléatoires et modestes dans UIKit).
Rob
2
@matt Ouais, j'ai vu un comportement similaire. J'ai donc répété mon exercice avec NSImage/ UIImageobjets et manifesté le problème de manière plus cohérente (et, franchement, c'est un exemple plus courant du problème, car l'utilisation maximale de la mémoire n'est souvent problématique que lorsqu'il s'agit d'objets plus grands; un exemple pratique de cela pourrait être une routine redimensionnant un tas d'images). J'ai également reproduit le comportement appelant le code Objective-C qui créait explicitement des objets de libération automatique. Ne vous méprenez pas: je pense que nous avons besoin de pools de libération automatique dans Swift moins souvent que dans Objective-C, mais cela a toujours un rôle à jouer.
Rob
1
J'ai trouvé un exemple qui fonctionne! Appelez simplement NSBundle à pathForResource:ofType:plusieurs reprises.
mat
1
Mon pathForResource:ofType:exemple ne fonctionne plus dans Xcode 6.3 / Swift 1.2. :)
matt
4

Si vous l'utilisiez dans le code Objective-C équivalent, vous l'utiliseriez dans Swift.

Swift sera-t-il assez intelligent pour savoir que la variable numérique devrait être libérée après la première}

Seulement si Objective-C le fait. Les deux fonctionnent selon les règles de gestion de la mémoire Cocoa.

Bien sûr, ARC sait que cela numbersort de la portée à la fin de cette itération de la boucle, et s'il la retient, il la libère là-bas. Cependant, cela ne vous indique pas si l'objet a été automatiquement publié, car -[NSNumber numberWithInt:] il peut avoir renvoyé ou non une instance de publication automatique. Vous ne pouvez pas le savoir, car vous n’avez pas accès à la source de -[NSNumber numberWithInt:].

newacct
la source
1
Si Swift se comporte de la même manière que Objective-C pour cela, pourquoi la présentation mentionnait "Travailler avec Objective-C?" Plus précisément?
Ethan le
9
@Ethan Il semblerait que les objets Swift natifs ne soient pas des objets à libération automatique, et la autoreleasepoolconstruction est totalement inutile. Mais si votre code Swift gère des objets Objective-C (y compris des objets Cocoa), ceux-ci suivent des modèles de libération automatique, et donc la autoreleasepoolconstruction devient utile.
Rob du
J'obtiens que "L'autoreleasepool vous permet de gérer explicitement quand les objets autorelease sont désalloués dans Swift" mais pourquoi le voudrais-je? Pourquoi le compilateur ne peut-il pas / ne le fait-il pas pour moi? J'ai dû ajouter mon propre autoreleasepool pour empêcher VM de traverser le toit dans une boucle serrée d'énormes manipulations de cordes. Il était évident pour moi où il fallait l'ajouter, et cela fonctionnait parfaitement. Pourquoi le compilateur n'a-t-il pas pu le faire? Le compilateur pourrait-il être rendu plus intelligent pour faire du bon travail?
vonlost le