Qu'est-ce qu'une fermeture ?
sobes.tech IA
Réponse de l'IA
La fermeture (closure) en Swift est un bloc autonome de fonctionnalités ({}) qui peut être transmis et utilisé dans le code. Les fermetures peuvent capturer et stocker des références à n'importe quelle constante ou variable du contexte dans lequel elles sont définies.
Exemples d'utilisation :
- En tant qu'arguments de fonctions (par exemple, gestionnaires de complétion).
- Pour définir le comportement lors de l'énumération de collections (par exemple, en utilisant les méthodes
map,filter,reduce,sorted). - Pour exécuter du code de manière différée.
Syntaxe :
// Syntaxe de base
{ (paramètres) -> typeDeRetour in
déclarations
}
// Exemple de fermeture prenant un Int et renvoyant un String
let integerToString: (Int) -> String = { (number: Int) -> String in
return "Numéro : \(number)"
}
Caractéristiques :
- Capture automatique des variables.
- Possibilité de définir des fermetures sans spécifier explicitement les types de paramètres et la valeur de retour (sucres syntaxiques).
- Utilisation de noms abrégés pour les paramètres ($0, $1, etc.).
- Syntaxe de fermeture avec trailing closure.
Capture de variables :
Une fermeture peut capturer des variables de son environnement. Par défaut, la capture se fait par référence. Si une fermeture est utilisée après que la variable d'origine a quitté le domaine, la fermeture conserve toujours l'accès à celle-ci.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0 // Variable du contexte externe
let incrementer: () -> Int = { // Fermeture
runningTotal += amount // Capture runningTotal et amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // Sortie : 10
print(incrementByTen()) // Sortie : 20
Listes de capture (Capture Lists) :
Utilisées pour indiquer explicitement comment les variables doivent être capturées - par valeur ou par référence, et pour éviter les cycles de références fortes (cycles de rétention).
class MyClass {
var value = 0
lazy var myClosure: () -> Void = { [self, value] in // Capture de self par référence, de value par valeur
print("Valeur de self.value : \(self.value)")
print("Valeur capturée : \(value)")
}
deinit {
print("Instance de MyClass libérée")
}
}
Pour éviter les cycles de références fortes lors de la capture d'objets de classes, utilisez la syntaxe [weak self] ou [unowned self].
class ViewController {
var dataFetcher: DataFetcher?
func fetchData() {
dataFetcher?.fetch { [weak self] result in // Capture faible de self
guard let self = self else { return } // Vérification de l'existence de self
// Traitement du résultat
}
}
}
class DataFetcher {
var completionHandler: ((Result<String, Error>) -> Void)?
func fetch(completion: @escaping (Result<String, Error>) -> Void) {
self.completionHandler = completion
// Opération asynchrone...
}
}