Logo de Swift en orange sur fond gris qui sert de hero de présentation de la formation sur les fondamentaux de Swift

Closure

Une closure, c’est un morceau de code que tu peux écrire directement et utiliser facilement dans ton programme. C’est un peu comme une mini-fonction, mais en plus flexible.

La grande différence avec une fonction, c’est que la closure peut se souvenir de ce qui se passe autour d’elle, comme des variables ou des constantes définies juste avant. Tu peux l’écrire, la garder dans une variable, et même la passer à une autre fonction pour dire : “Fais ça avec ce morceau de code”.

Pourquoi apprendre les closures ?

Elles te permettent d’écrire du code plus compact et plus lisible.

Elles sont parfaites pour faire des choses répétitives ou sur-mesure, comme trier une liste ou définir des actions à réaliser plus tard.

Tu vas les croiser partout dans Swift UI, alors mieux vaut bien comprendre les bases !

Les closures peuvent sembler abstraites au départ, donc le but de ce cours est de démystifier la notion en montrant qu’elles ne sont qu’une manière différente d’écrire et de manipuler du code. Voici une progression claire pour les rendre compréhensibles et utiles.

 Comparaison avec une func

Sur le papier, une fonction et une closure se ressemblent beaucoup. La principale différence est que la closure n’a pas de nom. Si on regarde leur syntaxe, elles peuvent toutes les deux :

Prendre des paramètres (typés).

Retourner un type.

Voici une comparaison claire pour que tu voies la similitude :


func add(a: Int, b: Int) -> Int {
    return a + b
}

let result = add(a: 3, b: 4)
print(result) 
// Lecture dans la console -> 7

Paramètres a: Int et b: Int (deux nombres entiers).

Retour Int (le résultat est un nombre entier).


let addClosure: (Int, Int) -> Int = { (a: Int, b: Int) in
    return a + b
}

let result = addClosure(3, 4)
print(result)
// Lecture dans la console -> 7

Paramètres (a: Int, b: Int) (comme la fonction).

Retour Int (le type du résultat est aussi précisé).

 

Ce qu’il faut retenir, c’est qu’une fonction a un nom (ici, add) et qu’elle est définie par un mot-clé (func), tandis que la closure n’a pas de nom et est souvent assignée à une variable ou utilisée directement.

Jusque-là, c’est très simple. C’est ce qu’on appelle une fonction anonyme dans d’autres langages. Ça te permet d’avoir un bloc de code à la volée, sans avoir à définir une fonction. Maintenant, on va continuer à approfondir l’apprentissage des closures avec ce qui fait leur puissance : leur capacité à capturer le contexte externe.

 Capturer le contexte externe


var counter = 0

let increment = {
    counter += 1
    print("Compteur : \(counter)")
}

increment() 
increment()
// Lecture dans la console -> Compteur : 1
// Lecture dans la console -> Compteur : 2

Capturer le contexte, ça veut simplement dire que la closure pourra lire les données externes à elle-même. Ici, elle peut lire et travailler sur la variable counter, ce qui n’est pas possible avec une fonction.

 Closures en tant que paramètres de fonction


func goTask(action: () -> Void) {
    print("Début de la tâche.")
    action()
    print("Fin de la tâche.")
}

goTask{
    print("Faire la vaisselle...")
}


/* 
Lecture dans la console -> 
	Début de la tâche.
    Faire la vaisselle...
    Fin de la tâche.
*/

La fonction goTask() accepte une closure comme paramètre, spécifiée par action: () -> Void. (En Swift, Void signifie que la closure n’a ni retour, ni valeur à fournir.)

Cette approche rend la fonction beaucoup plus flexible, tu peux adapter son comportement en lui passant la logique que tu veux exécuter au moment de son utilisation.


func goTask(action: () -> Void) {
    print("Début de la tâche.")
    action()
    print("Fin de la tâche.")
}
var number = 2

goTask {
    number += 1
    print(number)
}

/* 
Lecture dans la console ->
	Début de la tâche.
	3
	Fin de la tâche.
*/

Quand tu appelles ta fonction effectuerTache et que tu lui passes une closure, cette dernière contient le code que tu veux exécuter. Tu as le contrôle total sur ce que fait la closure, tant qu’elle respecte la signature attendue (dans ce cas, () -> Void).

 Simplifications des closures


//Avant
let addClosure: (Int, Int) -> Int = { (a: Int, b: Int) in
    return a + b
}

//Après
let addClosure = { (a, b) in a + b }

Swift supprime les éléments redondants grâce à sa capacité à deviner les types. Le type (Int, Int) -> Int est automatiquement déduit en fonction de l’utilisation ou du contexte. De plus, comme le corps de la closure ne contient qu’une seule ligne, le mot-clé return est omis, car Swift comprend automatiquement que cette ligne est la valeur retournée.


let addClosure = { $0 + $1 }

La closure devient ultra compacte grâce à l’utilisation des paramètres automatiques ($0, $1, etc.).

$0 Représente le premier paramètre de la closure.

$1 Représente le deuxième paramètre de la closure.

Avec cette syntaxe, il n’est plus nécessaire de nommer les paramètres (a, b) ou de spécifier leur type, car Swift devine tout automatiquement à partir du contexte.

 Closures et Fonctions de Haute-Ordre

Les closures sont couramment utilisées avec les fonctions de haute-ordre, qui sont des fonctions qui prennent des fonctions (ou des closures) en paramètres ou qui retournent des fonctions (ou des closures).

Explication de la Syntaxe $0 dans les Fonctions de Haute-Ordre

Lorsque tu utilise des fonctions de haute-ordre comme map, filter et reduce , tu peux utiliser la syntaxe abrégée pour référencer les paramètres des closures. Cette syntaxe utilise des symboles comme $0, $1, etc., pour représenter les arguments de la closure. Cette notation permet de rendre le code plus concis et lisible.

map

let names = ["Harry", "Hermione", "Ron"]
let uppercasedNames = names.map { $0.uppercased()}
print(uppercasedNames)

Lecture dans la console ->
["HARRY", "HERMIONE", "RON"]
La fonction map est utilisée pour transformer chaque élément d’une collection en appliquant une fonction à chaque élément, et retourne une nouvelle collection contenant les éléments transformés.

filter


let numbers = [1, 2, 3, 4, 5, 6]
let evenNumbers = numbers.filter { $0 % 2 == 0 }
print(evenNumbers)

Lecture dans la console ->
[2, 4, 6]
La fonction filter est utilisée pour filtrer les éléments d’une collection en fonction d’une condition spécifiée. Elle retourne une nouvelle collection contenant seulement les éléments qui satisfont la condition.

reduce


let scores = [10, 20, 30, 40]
let totalScore = scores.reduce(0) { $0 + $1 }
print(totalScore)

Lecture dans la console ->
100
La fonction reduce est utilisée pour combiner tous les éléments d’une collection en une seule valeur en appliquant une fonction de combinaison. Elle prend une valeur initiale et une fonction de combinaison qui spécifie comment combiner les éléments.

Exercices Pratiques

Exo closure

Télécharger le playground

Accède aux consignes directement en téléchargeant le playground.

⚠️ Les consignes que tu trouveras dans le playground ne sont pas verrouillées. Fais attention à ne pas les effacer par inadvertance ! 

Objectif

Les closures en Swift sont un outil puissant et essentiel pour écrire un code concis, flexible et réutilisable. Elles te permettent de capturer le contexte environnant, de personnaliser le comportement des fonctions, et de simplifier des tâches répétitives. Comprendre les closures te donnera les clés pour tirer pleinement parti de nombreuses fonctionnalités de Swift, comme les collections, les tâches asynchrones, et les interactions dynamiques. Avec les closures, tu pourras rendre ton code plus modulaire, clair, et adaptable aux besoins de ton application. Apprendre à les maîtriser, c’est poser une base solide pour écrire du code Swift moderne et performant.

Quiz

Après un peu de pratique, il est temps de te tester avec un petit quiz pour vérifier si tout est clair pour toi. Prends ton temps, lis bien les questions, et bonne chance..

Note

Les paramètres automatiques comme $0, $1 sont pratiques pour les closures simples, mais dans les cas complexes, il est préférable de nommer les paramètres pour améliorer la lisibilité.

Exercices Pratiques

Exo closure

Télécharger le playground

Accède aux consignes directement en téléchargeant le playground.

⚠️ Les consignes que tu trouveras dans le playground ne sont pas verrouillées. Fais attention à ne pas les effacer par inadvertance ! 

Objectif

Les closures en Swift sont un outil puissant et essentiel pour écrire un code concis, flexible et réutilisable. Elles te permettent de capturer le contexte environnant, de personnaliser le comportement des fonctions, et de simplifier des tâches répétitives. Comprendre les closures te donnera les clés pour tirer pleinement parti de nombreuses fonctionnalités de Swift, comme les collections, les tâches asynchrones, et les interactions dynamiques. Avec les closures, tu pourras rendre ton code plus modulaire, clair, et adaptable aux besoins de ton application. Apprendre à les maîtriser, c’est poser une base solide pour écrire du code Swift moderne et performant.

Quiz

Après un peu de pratique, il est temps de te tester avec un petit quiz pour vérifier si tout est clair pour toi. Prends ton temps, lis bien les questions, et bonne chance..

Note

Les paramètres automatiques comme $0, $1 sont pratiques pour les closures simples, mais dans les cas complexes, il est préférable de nommer les paramètres pour améliorer la lisibilité.