Développement Web

Maîtriser les bases du langage Swift 6 : types, optionals, fonctions

12 min de lecture

Swift est un langage typé, sûr et compact. Sa surface syntaxique est plus petite que celle de C++ ou Java, et la plupart des concepts s’expriment de façon directe. Ce tutoriel parcourt les briques fondamentales du langage dans un Playground Xcode : déclaration de variables, types primitifs, optionals, fonctions, closures, value types et reference types. À la fin, vous aurez écrit et exécuté chaque exemple, suffisamment pour démarrer SwiftUI sans bloquer sur la syntaxe.

📘 Guide principal de la série : Développer une application iOS avec Swift et SwiftUI : panorama 2026. Le présent tutoriel se concentre sur le langage ; pour l’environnement et la mise en place, voir le tutoriel précédent sur l’installation de Xcode.

Prérequis

  • Xcode 26 installé sur macOS Tahoe (voir le tutoriel d’installation si besoin).
  • Connaissances de base en programmation dans n’importe quel langage typé (variables, fonctions, types primitifs).
  • Temps estimé : 60 à 90 minutes en suivant tous les exemples.

Étape 1 — Créer un Playground Xcode

Un Playground est un fichier Swift interactif qui exécute le code au fil de la saisie et affiche les résultats dans la marge droite. C’est l’outil idéal pour apprendre la syntaxe sans monter un projet d’app complet. La création se fait depuis le menu File de Xcode.

Dans Xcode : File > New > Playground (⌥⇧⌘N). Dans le sélecteur, choisir macOS > Blank puis Next. Nommer le fichier SwiftBasics.playground et le sauvegarder dans un dossier de travail. Xcode ouvre le Playground avec une ligne d’exemple var greeting = "Hello, playground".

var greeting = "Hello, playground"
print(greeting)

Appuyer sur le bouton de lecture à gauche de la première ligne (ou ⇧⏎) exécute jusqu’à cette ligne. Dans la marge droite, la valeur "Hello, playground" apparaît à côté de la déclaration, et print affiche son contenu dans la console (View > Debug Area > Show Debug Area si elle n’est pas visible).

Étape 2 — Variables, constantes et inférence de type

Swift distingue deux modes de stockage : var pour les valeurs modifiables, let pour les constantes. L’inférence de type devine le type quand on l’omet, mais on peut toujours l’annoter explicitement avec : Type. L’annotation explicite est utile quand l’inférence ne devine pas ce qu’on veut.

let pi = 3.14159
var compteur = 0
compteur += 1

let nom: String = "Aïcha"
let age: Int = 28
let actif: Bool = true

La ligne compteur += 1 compile parce que compteur est déclaré var. Tenter pi = 4.0 produirait l’erreur « Cannot assign to value: ‘pi’ is a ‘let’ constant ». La convention en Swift est d’utiliser let partout par défaut et de passer à var uniquement quand la mutation est nécessaire. Le compilateur signale d’ailleurs en avertissement les var qu’on aurait pu déclarer let.

Étape 3 — Types primitifs et conversions

Les types de base sont Int, Double, Float, String, Bool, ainsi que les collections Array, Dictionary, Set. Swift est strict sur les conversions : on ne peut pas additionner un Int et un Double sans conversion explicite.

let ageInt: Int = 28
let tauxDouble: Double = 1.5
// let invalide = ageInt + tauxDouble  // ❌ Erreur de compilation
let valide: Double = Double(ageInt) + tauxDouble
print(valide)  // 29.5

La ligne commentée produirait « Binary operator ‘+’ cannot be applied to operands of type ‘Int’ and ‘Double’ ». Cette rigueur évite toute une famille de bugs de précision implicites présents en JavaScript ou en Python. La règle pratique : convertir explicitement quand on mélange des types numériques différents, et préférer Double à Float sauf besoin spécifique (graphismes Metal, calculs scientifiques en simple précision).

Étape 4 — Optionals : la pierre angulaire

Aucun concept Swift n’est plus important que les optionals. Un optional est un type qui peut contenir soit une valeur, soit nil. On l’écrit en suffixant le type d’un point d’interrogation : String? signifie « une chaîne ou rien ». Le compilateur refuse de manipuler une valeur optional comme si elle était garantie présente — il faut la déballer.

let prenomBrut: String? = "Mariam"
let prenomVide: String? = nil

// 1. Optional binding avec if let
if let prenom = prenomBrut {
    print("Bonjour \(prenom)")
} else {
    print("Pas de prénom")
}

// 2. Guard let (sort tôt si nil)
func saluer(_ p: String?) {
    guard let valeur = p else {
        print("Valeur manquante")
        return
    }
    print("Bonjour \(valeur)")
}
saluer(prenomVide)  // Valeur manquante

// 3. Nil-coalescing
let affichage = prenomVide ?? "Anonyme"
print(affichage)  // Anonyme

// 4. Optional chaining
let longueur = prenomBrut?.count
print(longueur as Any)  // Optional(6)

Quatre patterns coexistent. if let entre dans un bloc seulement si la valeur est présente. guard let sort tôt si elle est absente — utile au début d’une fonction. ?? fournit une valeur de repli. ?. chaîne des appels en court-circuitant si nil. Le déballage forcé avec ! existe mais doit être réservé aux cas où l’absence de valeur est impossible — sinon il provoque un crash au runtime avec le message « Unexpectedly found nil while unwrapping an Optional value ».

Étape 5 — Fonctions et arguments nommés

Les fonctions Swift se déclarent avec func. La syntaxe d’appel utilise par défaut les noms des paramètres comme étiquettes, ce qui produit des appels très lisibles. On peut renommer ou supprimer l’étiquette d’un paramètre selon le besoin.

func saluer(personne nom: String, en langue: String = "fr") -> String {
    switch langue {
    case "fr": return "Bonjour \(nom)"
    case "en": return "Hello \(nom)"
    case "es": return "Hola \(nom)"
    default: return nom
    }
}

let salutation = saluer(personne: "Fatou", en: "es")
print(salutation)  // Hola Fatou

// Argument sans étiquette : utiliser _
func carre(_ x: Int) -> Int { x * x }
print(carre(7))  // 49

L’étiquette externe personne apparaît à l’appel, tandis que nom est le nom utilisé dans le corps. Le paramètre langue a une valeur par défaut "fr", ce qui le rend optionnel à l’appel. La fonction carre utilise _ comme étiquette externe pour s’appeler simplement carre(7) sans étiquette. Le mot-clé return est facultatif pour une fonction à une seule expression — c’est pourquoi { x * x } suffit.

Étape 6 — Closures et fonctions d’ordre supérieur

Une closure est un bloc de code anonyme qui capture les variables de son environnement. Les méthodes des collections en font un usage intensif : map, filter, reduce, compactMap, sorted. Le sucre syntaxique de Swift rend les closures très compactes.

let nombres = [3, 1, 4, 1, 5, 9, 2, 6]

// Forme verbeuse
let doubles = nombres.map({ (n: Int) -> Int in return n * 2 })

// Forme compacte par inférence
let triples = nombres.map { $0 * 3 }

// Filter + reduce chaînés
let sommeImpairs = nombres
    .filter { $0 % 2 == 1 }
    .reduce(0, +)

print(doubles)        // [6, 2, 8, 2, 10, 18, 4, 12]
print(triples)        // [9, 3, 12, 3, 15, 27, 6, 18]
print(sommeImpairs)   // 19

La forme compacte exploite trois facilités : l’inférence de type sur les paramètres, le trailing closure qui sort la closure des parenthèses, et les noms abrégés $0, $1… pour les arguments positionnels. Cette compacité rend le code de transformation de données très lisible une fois la convention assimilée. Les nouveaux développeurs préfèrent souvent la forme verbeuse pour comprendre ; il est tout à fait acceptable de garder ce style le temps de s’habituer.

Étape 7 — Structures et value types

Les struct représentent des valeurs : elles sont copiées à l’affectation et au passage d’argument. Cette sémantique élimine une large famille de bugs de partage d’état. La plupart des types Swift utilisés au quotidien — y compris String, Array, Dictionary — sont des structs.

struct Personne {
    var nom: String
    var age: Int

    func presentation() -> String {
        "\(nom), \(age) ans"
    }

    mutating func vieillir() {
        age += 1
    }
}

var alice = Personne(nom: "Alice", age: 30)
var copie = alice
copie.vieillir()

print(alice.age)   // 30 (non modifiée)
print(copie.age)   // 31

La copie modifiée n’affecte pas l’originale parce qu’à l’affectation var copie = alice, Swift duplique les données. Une méthode qui modifie l’instance doit être marquée mutating ; le compilateur empêche d’appeler vieillir() sur une constante let. Cette discipline garantit qu’on sait toujours quel chemin du code peut modifier une valeur.

Étape 8 — Classes et reference types

Les class représentent des références : plusieurs variables peuvent pointer vers la même instance. Les classes sont nécessaires quand on a besoin d’identité partagée, d’héritage, ou de cycle de vie contrôlé via deinit. SwiftUI utilise très peu de classes — la plupart de la couche UI est en structs.

class Compteur {
    var valeur: Int = 0
    func incrementer() { valeur += 1 }
}

let a = Compteur()
let b = a
a.incrementer()

print(a.valeur)  // 1
print(b.valeur)  // 1 — même instance

a et b pointent vers la même instance ; modifier l’un affecte l’autre. C’est la sémantique attendue pour des objets manipulant un état partagé (un connecteur réseau, un cache). La règle de pouce : commencer par une struct ; passer à class uniquement quand l’identité partagée, l’héritage ou un deinit sont strictement nécessaires.

Étape 9 — Enum avec valeurs associées

Les enums Swift dépassent largement les enums C : chaque cas peut porter des valeurs associées d’un type différent. Cette puissance permet de modéliser des résultats, des états, des messages avec une rigueur que le compilateur valide via les switch exhaustifs.

enum ResultatReseau {
    case succes(donnees: Data)
    case echec(message: String, code: Int)
    case enCours
}

func traiter(_ r: ResultatReseau) {
    switch r {
    case .succes(let donnees):
        print("Reçu \(donnees.count) octets")
    case .echec(let message, let code):
        print("Erreur \(code) : \(message)")
    case .enCours:
        print("En cours…")
    }
}

traiter(.echec(message: "Timeout", code: 504))

Le switch est exhaustif — si on oublie le cas .enCours, le compilateur signale « Switch must be exhaustive ». Cette sécurité empêche d’introduire un nouveau cas dans l’enum sans mettre à jour tous les consommateurs. Pour des résultats d’API, le type Result<Succès, Erreur> de la bibliothèque standard remplit ce rôle de façon plus concise.

Étape 10 — Protocoles et extensions

Les protocoles décrivent un contrat ; tout type qui s’y conforme doit fournir les exigences. Les extensions permettent d’ajouter du comportement à un type existant, y compris des types de la bibliothèque standard. Cette combinaison remplace la majorité des cas d’héritage de classes.

protocol Nommable {
    var nomComplet: String { get }
}

struct Etudiant: Nommable {
    let prenom: String
    let nom: String
    var nomComplet: String { "\(prenom) \(nom)" }
}

extension Etudiant {
    func saluer() -> String {
        "Bonjour, je suis \(nomComplet)"
    }
}

let e = Etudiant(prenom: "Aminata", nom: "Diop")
print(e.saluer())  // Bonjour, je suis Aminata Diop

Le protocole Nommable exige une propriété calculée nomComplet. La struct Etudiant s’y conforme en la fournissant. L’extension ajoute une méthode saluer() sans toucher à la déclaration originelle — ce pattern, omniprésent en Swift, permet d’organiser le code par fonctionnalité plutôt que par hiérarchie de classes.

Erreurs fréquentes en démarrage Swift

Erreur Cause Solution
« Value of optional type ‘String?’ must be unwrapped » Manipulation directe d’un optional Utiliser if let, guard let ou ?. pour déballer
« Cannot assign to value: ‘x’ is a ‘let’ constant » Tentative de modifier une constante Déclarer en var si la mutation est intentionnelle
« Switch must be exhaustive » Cas d’enum non couvert dans un switch Ajouter le cas manquant ou un default:
« Type ‘X’ does not conform to protocol ‘Y’ » Une exigence du protocole n’est pas implémentée Vérifier la signature exacte (nom, types, get/set)
Crash « Unexpectedly found nil » Déballage forcé avec ! sur un nil Remplacer par ?., ?? ou guard let
« Cannot use mutating member on immutable value » Méthode mutating sur une let Déclarer en var ou retirer mutating

Foire aux questions

Faut-il toujours préférer struct à class ?

Par défaut oui. Une struct suffit pour 80 % des modèles métier et offre une sémantique de valeur plus prévisible. Passer à class est justifié quand l’identité partagée est nécessaire (un singleton, un connecteur), quand l’héritage Objective-C est requis (UIKit), ou quand on a besoin d’un deinit pour libérer des ressources externes.

Que vaut Swift face à Kotlin ou TypeScript ?

Swift partage avec Kotlin et TypeScript les optionals, les fonctions de première classe, l’inférence de type et les data classes. Sa différence principale est l’absence de runtime VM : un binaire Swift est natif, ce qui réduit le temps de démarrage des apps. Pour un développeur Kotlin, le passage à Swift se fait en quelques jours.

À quoi servent les actor introduits avec Swift Concurrency ?

Un actor est un type référence qui sérialise les accès à son état. C’est l’outil de Swift pour modéliser un objet partagé entre tâches concurrentes sans data race. Pour les premiers projets, on n’a pas besoin d’actor ; ils deviennent utiles dès qu’on partage un cache ou un client réseau entre plusieurs tâches.

Le déballage forcé avec ! est-il toujours mauvais ?

Non, mais il est rarement justifié. Les cas légitimes sont les @IBOutlet liés à un storyboard, certaines initialisations partielles, et les conversions qui ne peuvent jamais échouer (par exemple URL(string: "https://google.com")!). Dans tous les autres cas, guard let ou ?? sont plus sûrs.

Comment apprendre Swift sans Mac ?

La toolchain Swift fonctionne sur Linux et Windows pour le langage seul. Sur replit.com ou via Docker (image swift:6.3) on peut exécuter du Swift CLI. Le développement iOS lui-même reste exclusif au Mac à cause de Xcode et des simulateurs.

Quel livre officiel pour aller plus loin ?

The Swift Programming Language publié par Apple est la référence canonique : gratuit, exhaustif, mis à jour à chaque release. Pour un parcours plus narratif, le tutoriel officiel SwiftUI Tutorials sur developer.apple.com est complémentaire.

Tutoriels suivants conseillés

Ressources officielles

Service ITSkillsCenter

Site ou application web sur mesure

Conception Pro + Nom de domaine 1 an + Hébergement 1 an + Formation + Support 6 mois. Accès et code livrés. À partir de 350 000 FCFA.

Demander un devis
Publicité