web-dev-qa-db-fra.com

Est-il nécessaire d'utiliser [non propriétaire] dans les fermetures de UIView.animateWithDuration (...)?

    UIView.animateWithDuration(1,
        animations: { [unowned self] in
            self.box.center = self.boxTopRightPosition
        },
        completion: { [unowned self] completed in
            self.box.hidden = true
    })

Est-il nécessaire d'éviter les fuites de mémoire?

33
WildCat

Non, ce n'est pas nécessaire dans ce cas. animations et completion ne sont pas conservés par self, il n'y a donc aucun risque de cycle de rétention important.

42
Kirsteins

Eh bien, "nécessaire" n'est pas la même chose que "recommandé". Si votre question est de savoir si cela est nécessaire, la réponse de @Kirsteins est correcte, mais imaginez le cas où vous souhaitez animer quelque chose dans votre contrôleur de vue après un certain travail, mais que votre contrôleur de vue a été publié (car il ne fait plus partie de la hiérarchie des vues. ou toute autre raison). Dans ce cas, si vous n'utilisez pas [weak self], votre contrôleur de vue ne sera pas libéré avant la fin de l'animation, car vous la conservez dans le bloc d'animation, mais est-il judicieux de conserver cette dernière jusqu'à l'animation d'un élément qui ne fait pas partie de l'animation? la vue plus?

Donc, en peu de mots, vous ne devez pas besoin utiliser une référence weak à vous-même lorsque vous animez UIKit. Toutefois, vous n'avez pas besoin de conserver votre vue si elle est publiée car une animation sans vue ne Cela n’a pas de sens, donc utiliser weak est une bonne option.

17
Pablo A.

@Plabo, comme @Kirsteins l'a dit, les animations et l'achèvement ne sont pas conservés par eux-mêmes. Ainsi, même si vous démarrez une animation et pour une raison quelconque, votre contrôleur de vue a été publié, il sera désalloué instantanément. Donc, vous n'avez pas besoin de «soi» capturé. Considérez l'exemple idiot ci-dessous:

class ViewController: UIViewController {

    @IBOutlet weak var button : UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        print("viewDidLoad ViewController")
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        UIView.animate(withDuration: 20, animations: {
            self.button.frame = CGRect(x: 0, y: 300, width: 30, height: 30)
        }) { finished in
            self.button.frame = CGRect(x: 0, y: 100, width: 30, height: 30)
        }
    }

    deinit {
        print("deinit ViewController")
    }

}

Dès qu'il sera désalloué, le désinitialiseur sera appelé et l'achèvement ne sera jamais exécuté.

6
lhmgrassi

Non ce n'est pas nécessaire. Comme Kirsteins dit: 

Non, ce n'est pas nécessaire dans ce cas. les animations et la réalisation ne sont pas retenues par soi-même, il n'y a donc aucun risque de fort cycle de conservation.

Mais lhmgrassi dit: 

Dès qu'il sera désalloué, le désinitialiseur sera appelé et l'achèvement ne sera jamais exécuté.

Je ne pense pas que c'est vrai. Le bloc d'achèvement sera appelé toujours . Et si vous utilisez un moi fort, votre objet ne sera pas désalloué tant que le bloc d'achèvement n'aura pas été exécuté.

Toutefois, si vous utilisez un [weak self], votre objet n'est pas (temporaire) conservé par le bloc d'achèvement et peut être libéré avant le déclenchement du bloc d'achèvement. Le bloc d'achèvement est toujours activé, mais self est déjà nil

Si vous utilisez un [unowned self] dans votre gestionnaire d'achèvement, votre objet peut également être désalloué avant l'appel du gestionnaire d'achèvement, ce qui pourrait provoquer un blocage! 

J'ai fait un exemple illustrant ceci. 

 [gif illustrating the issue

La source complète peut être trouvée sur Github

3
Tieme

Au contraire. Vous voulez self continuer à exister suffisamment longtemps pour que le bloc d'achèvement soit appelé. Donc, avoir self être fort et retenu par le gestionnaire d'achèvement qui s'échappe est un bien chose.

L'inquiétude qui pousse généralement les gens à utiliser weak self est un retenue cycle . Mais ce n'est pas ça. Un cycle de conservation correspond au moment où self conserve la fermeture qui conserve self, ce qui provoque une fuite, car self ne peut plus jamais être libéré. Mais ce n'est pas du tout cette situation. la fermeture, et donc self, est conservée, mais pas par self! Il y a donc des retards temporaires, mais c'est bien , pas mal.

1
matt