Closures en Swift

Apprenez à emballer des fonctionnalités pour les stocker, les réutiliser et les simplifier.

Voir sur YouTube

Les closures en Swift sont des blocs de code auto-contenus qui peuvent être passés et utilisés dans votre code. Elles sont similaires aux fonctions, mais elles peuvent capturer et stocker des références aux variables et constantes de leur contexte environnant. En d'autres termes, une closure peut capturer des valeurs des variables locales autour d'elle, ce qui la rend très puissante pour certains types de programmation, comme les callbacks, les filtres, les mappages, etc.

Syntaxe de Base d'une Closure

La syntaxe d'une closure peut être compacte ou plus détaillée, selon la situation. Voici la syntaxe de base :

{ (parameters) -> returnType in
    // Code à exécuter
}
  • parameters : Les paramètres que la closure accepte, identiques à ceux des fonctions.
  • returnType : Le type de la valeur retournée par la closure. Il peut être omis si la closure ne retourne rien.
  • in : Mot-clé qui sépare la liste des paramètres et le type de retour du corps de la closure.

Exemples de Closures

Closure simple qui additionne deux nombres

let sumClosure = { (a: Int, b: Int) -> Int in
    return a + b
}
let result = sumClosure(3, 5)
print(result)  // Affiche : 8

Dans cet exemple :

  • La closure sumClosure accepte deux paramètres a et b de type Int.
  • Elle retourne un Int qui est la somme de a et b.
  • sumClosure est ensuite appelée avec les arguments 3 et 5.

Closure sans paramètres ni retour

let greetClosure = {
    print("Hello, world!")
}
greetClosure()  // Affiche : "Hello, world!"

Cette closure n'accepte aucun paramètre et ne retourne aucune valeur. Elle se contente d'exécuter le code à l'intérieur, qui ici affiche un message.

Closures comme Paramètres de Fonction

Les closures sont souvent utilisées comme paramètres dans des fonctions, notamment pour des opérations asynchrones ou des transformations de collections.

Exemple avec sort :

let numbers = [5, 2, 9, 1, 7]
let sortedNumbers = numbers.sorted(by: { (a: Int, b: Int) -> Bool in
    return a < b
})
print(sortedNumbers)  // Affiche : [1, 2, 5, 7, 9]

Dans cet exemple :

  • La méthode sorted(by:) utilise une closure pour déterminer l'ordre de tri.
  • La closure compare deux éléments et retourne un Bool indiquant si le premier élément doit précéder le second.

Syntaxe Réduite des Closures

Swift permet de simplifier la syntaxe des closures, surtout dans les cas où le contexte est évident.

Exemple avec Inference de Type :

let sortedNumbers = numbers.sorted(by: { a, b in a < b })

Swift peut inférer les types des paramètres a et b, donc vous pouvez omettre leur type et le type de retour.

Utilisation de $0, $1, etc. :

let sortedNumbers = numbers.sorted(by: { $0 < $1 })

Swift fournit des noms abrégés pour les paramètres de closure ($0 pour le premier paramètre, $1 pour le second, etc.), ce qui permet de rendre la closure encore plus concise.

Trailing Closure Syntax :

Si une closure est le dernier paramètre d'une fonction, vous pouvez la sortir des parenthèses pour plus de clarté.

let sortedNumbers = numbers.sorted { $0 < $1 }

Capturer les Valeurs dans une Closure

Les closures peuvent capturer et stocker des références aux variables et constantes de leur contexte environnant.

Exemple :

func makeIncrementer(incrementAmount: Int) -> () -> Int {
    var total = 0
    let incrementer: () -> Int = {
        total += incrementAmount
        return total
    }
    return incrementer
}
let incrementByTen = makeIncrementer(incrementAmount: 10)
print(incrementByTen())  // Affiche : 10
print(incrementByTen())  // Affiche : 20

Dans cet exemple :

  • La fonction makeIncrementer retourne une closure qui capture la variable total.
  • Chaque fois que la closure est appelée, elle modifie et utilise la valeur de total, même si elle n'est plus dans la portée de la fonction d'origine.