Sobes.tech
Middle

Parlez-moi de la liste de capture en Swift.

sobes.tech IA

Réponse de l'IA

La liste de capture en Swift est utilisée pour gérer explicitement la capture de variables par les closures. Cela permet d'éviter les cycles de références fortes, en particulier lors de l'utilisation de self dans des closures utilisées à l'intérieur de classes. Les principaux types de capture sont : weak et unowned.

Type de capture Description Quand l'utiliser
weak Capture la variable comme optionnelle, sans augmenter le compteur de références. Sa valeur peut devenir nil. Lorsque l'objet du closure peut survivre à l'objet capturé.
unowned Capture la variable sans augmenter le compteur de références, mais on suppose que l'objet capturé vivra tant que le closure existe. Ce n'est pas une option. Lorsque l'objet du closure et l'objet capturé ont la même durée de vie, et que l'objet capturé ne sera pas nil avant la fin du closure.

Syntaxe de la liste de capture :

{ [liste de capture] (paramètres) -> typeDeRetour in
    // code
}

Exemple d'utilisation de weak self :

class MyClass {
    var value = 0

    func doSomethingLater() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
            guard let self = self else { return } // Vérification de nil
            self.value += 1
            print("La valeur est maintenant \(self.value)")
        }
    }
}

Exemple d'utilisation de unowned self :

class ViewController: UIViewController {
    var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        button = UIButton(type: .system)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
    }

    @objc func buttonTapped() {
        // unowned self n'est pas nécessaire dans ce cas, car le bouton existe tant que le ViewController existe.
        // Mais si le closure pouvait survivre au ViewController, unowned pourrait être approprié si
        // on est sûr que self ne deviendra pas nil.
        let action = { [unowned self] in
             self.view.backgroundColor = .blue
        }
        action()
    }
}

On peut capturer non seulement self, mais aussi toute autre variable accessible dans le closure. Par exemple, pour sauvegarder la valeur d'une variable au moment de la création du closure :

func createIncrementer(initialValue: Int) -> () -> Int {
    var currentValue = initialValue
    return { [initialValue] in // Capture initialValue par valeur
        currentValue += 1
        print("La valeur initiale était \(initialValue)") // initialValue conserve sa valeur
        return currentValue
    }
}

let incrementer = createIncrementer(initialValue: 5)
print(incrementer()) // Sortie : La valeur initiale était 5, puis 6
print(incrementer()) // Sortie : La valeur initiale était 5, puis 7