Cours Swift Complet 🍎
Les 12 chapitres essentiels — Optionals, protocols, enums, closures et l'écosystème Apple
🏠 Hub Programmation
🐍 Python
⚡ JavaScript
🔷 TypeScript
☁️ AWS Cloud Practitioner
Introduction et premier programme
print(« Nom: \(nom), Age: \(age) ») // String interpolation
Swift est simple. Pas besoin de main(), pas de ;, pas de header files. Un fichier .swift suffit. L'interpolation de string \(expression) est puissante : elle accepte n'importe quelle expression.
xcode-select –install
# Ou via Swift.org (Linux/Windows aussi)
# https://www.swift.org/install/
# REPL interactif
swift
# Exécuter un fichier
swift hello.swift
# Créer un package Swift
swift package init –type executable
swift run
# Compiler
swiftc hello.swift -o hello
| Caractéristique | Swift |
|---|---|
| Typage | Statique et fort avec inférence |
| Paradigme | Multi-paradigme : POO + fonctionnel + protocol-oriented |
| Mémoire | ARC (Automatic Reference Counting — pas de GC) |
| Sûreté | Optionals (pas de null crash), type-safe |
| Performance | Compilé (LLVM), performance proche du C |
| Usage | iOS, macOS, watchOS, tvOS, serveur (Vapor) |
| Convention | camelCase (fonctions/variables), PascalCase (types) |
Swift a remplacé Objective-C comme langage principal pour l'écosystème Apple. Plus sûr (optionals), plus lisible, et avec des features modernes (enums avec données, pattern matching, async/await). Il est aussi utilisé côté serveur avec Vapor.
Variables et types de données
let nom = « Alice » // Type inféré : String
let pi = 3.14159 // Double
let age: Int = 25 // Type explicite
// var = variable (mutable)
var score = 0
score += 10 // ✅ OK
// nom = « Bob » ❌ Erreur — let est immuable
Xcode vous avertit si vous utilisez var alors que la variable n'est jamais modifiée. Privilégiez toujours let — c'est le standard Swift pour du code sûr et prévisible.
| Type | Description | Exemple |
|---|---|---|
| Int | Entier (64 bits sur les systèmes modernes) | 42 |
| Double | Flottant 64 bits (par défaut) | 3.14 |
| Float | Flottant 32 bits | Float(3.14) |
| Bool | Booléen | true / false |
| String | Chaîne Unicode | « Hello \(name) » |
| Character | Un caractère Unicode | « A » as Character |
// Interpolation
let msg = « J'ai \(age) ans et \(age >= 18 ? « majeur » : « mineur ») »
// Multi-ligne
let texte = « » »
Première ligne
Deuxième ligne
« » »
// Méthodes
s.count // 11
s.isEmpty // false
s.uppercased() // « HELLO WORLD »
s.lowercased() // « hello world »
s.contains(« World ») // true
s.hasPrefix(« He ») // true
s.hasSuffix(« ld ») // true
s.replacingOccurrences(of: « World », with: « Swift »)
s.split(separator: » « ) // [« Hello », « World »]
s.trimmingCharacters(in: .whitespaces)
// Conversion
let n = Int(« 42 ») // Optional Int? (peut échouer)
let s = String(42) // « 42 »
Optionals
var nom: String? = « Alice » // String? = Optional
var age: Int? = nil // Pas de valeur
// ⚠️ On ne peut PAS utiliser un Optional directement
// print(nom) → Optional(« Alice ») — pas ce qu'on veut
// 1. if let — unwrap conditionnel (LE PLUS COURANT)
if let name = nom else
// 2. if let raccourci (Swift 5.7+) — même nom
if let nom
// 3. guard let — early exit (préféré dans les fonctions)
func greet(_ nom: String?)
// 4. ?? — valeur par défaut (nil coalescing)
let name = nom ?? « Inconnu » // « Alice » ou « Inconnu »
// 5. ?. — optional chaining
let count = nom?.count // Int? (nil si nom est nil)
// 6. ! — force unwrap (DANGEREUX — crash si nil)
let name = nom! // ⚠️ Crash si nil !
N'utilisez JAMAIS ! en production sauf si vous êtes 100% certain que la valeur n'est pas nil. C'est la source n°1 de crashs iOS. Préférez if let, guard let ou ??.
Structures de contrôle
if age >= 18 else
// if expression (Swift 5.9+)
let label = if age >= 18 else
// switch — EXHAUSTIF, pas de break (implicite), pas de fallthrough
switch grade
// switch avec ranges et where
switch age
// for-in — la seule boucle nécessaire
for i in 0..<5
for i in 0…5
for item in array
for (i, val) in array.enumerated()
for _ in 0..<3
// while, repeat-while (do-while)
while condition
repeat while condition
Collections
var nums: [Int] = [1, 2, 3] var names = [« Alice », « Bob »] // Type inféré
let empty: [String] = [] // Tableau vide
nums.append(4) // [1, 2, 3, 4]
nums.insert(0, at: 0) // [0, 1, 2, 3, 4]
nums.remove(at: 0) // [1, 2, 3, 4]
nums.removeLast() // [1, 2, 3]
nums.count // 3
nums.isEmpty // false
nums.contains(2) // true
nums.first // Optional(1)
nums.last // Optional(3)
nums.sorted() // Retourne un nouveau tableau trié
nums.reversed() // Retourne une vue inversée
// Set — non ordonné, éléments uniques
var tags: Set<String> = [« swift », « ios », « swift »] //
tags.insert(« mobile »)
tags.contains(« swift ») // true
tags.intersection(other) // éléments communs
tags.union(other) // tous les éléments
// Dictionary — clé/valeur
var ages: [String: Int] = [« Alice »: 25, « Bob »: 30]
ages[« Charlie »] = 28 // Ajouter/modifier
ages[« Alice »] // Optional(25) — toujours Optional !
ages[« Eve »] ?? 0 // 0 si absent
ages.removeValue(forKey: « Bob »)
for (nom, age) in ages
Structs et Classes
var alice = Person(name: « Alice », age: 25)
alice.birthday() // 26
// Struct = VALUE TYPE → copie à l'affectation
var bob = alice // bob est une COPIE indépendante
bob.age = 40 // alice.age n'est pas affecté
// Class = REFERENCE TYPE → partage la même instance
let car1 = Vehicle(brand: « Tesla »)
let car2 = car1 // car2 pointe vers la MÊME instance
car2.speed = 100 // car1.speed = 100 aussi !
Règle d'or Swift : préférez les Structs. Utilisez les classes uniquement pour l'héritage ou quand vous avez besoin de sémantique de référence. Apple recommande Struct par défaut — c'est plus sûr et plus performant.
| Critère | Struct (valeur) | Class (référence) |
|---|---|---|
| Copie | Copie indépendante | Partage la même instance |
| Héritage | ❌ Non | ✅ Oui |
| Mutabilité | Nécessite mutating | Pas besoin |
| Init | Memberwise auto | Manuelle |
| ARC | Non (stack) | Oui (heap) |
| Recommandé | Par défaut | Quand nécessaire |
Enums et Pattern Matching
enum Direction
let d: Direction = .north
// Enum avec raw values
enum Planet: Int
Planet.earth.rawValue // 3
Planet(rawValue: 1) // Optional(.mercury)
// Enum avec associated values (données par variante)
enum Result
let r: Result = .success(data: « Hello »)
// Pattern matching avec switch
switch r
Les enums Swift sont aussi puissants que ceux de Rust. Chaque case peut contenir des données différentes (associated values). Le switch doit être exhaustif — le compilateur garantit que tous les cas sont traités.
// CaseIterable — itérer sur tous les cas
for season in Season.allCases
Gestion d'erreurs
enum NetworkError: Error
// Fonction qui peut lancer une erreur
func fetchUser(id: Int) throws -> String
// do-catch
do catch NetworkError.notFound catch NetworkError.serverError(let code) catch
// try? — retourne nil si erreur
let user = try? fetchUser(id: –1) // nil
// try! — crash si erreur (comme force unwrap)
let user = try! fetchUser(id: 1) // ⚠️ Crash si erreur
func divide(_ a: Double, by b: Double) -> Result<Double, Error>
switch divide(10, by: 3)
Closures
let add =
add(3, 4) // 7
// Raccourci — type inféré, return implicite
let add: (Int, Int) -> Int =
// Trailing closure syntax
let nums = [3, 1, 4, 1, 5]
let sorted = nums.sorted // [1, 1, 3, 4, 5]
let sorted = nums.sorted(by: <) // Encore plus court
// map — transformer chaque élément
let doubled = nums.map // [2, 4, 6, 8, …]
// filter — garder les éléments qui satisfont la condition
let evens = nums.filter // [2, 4, 6, 8, 10]
// reduce — réduire à une seule valeur
let sum = nums.reduce(0, +) // 55
// compactMap — map + filtre nil
let strings = [« 1 », « abc », « 3 »]
let ints = strings.compactMap // [1, 3]
// flatMap — aplatir les tableaux imbriqués
let nested = [[1,2], [3,4], [5]]
let flat = nested.flatMap // [1, 2, 3, 4, 5]
// Chaîner
let result = nums
.filter
.map
.reduce(0, +) // (2+4+6+8+10)*3 = 90
// Autres méthodes
nums.first(where: ) // Optional(6)
nums.contains(where: ) // true
nums.allSatisfy // true
nums.min() // Optional(1)
nums.max() // Optional(10)
Generics
func swapValues<T>(_ a: inout T, _ b: inout T)
// Avec contrainte
func largest<T: Comparable>(_ a: T, _ b: T) -> T
// Struct générique
struct Stack<Element>
var stack = Stack<Int>()
stack.push(1)
stack.push(2)
stack.pop() // Optional(2)
Concurrence (async/await)
func fetchUser(id: Int) async throws -> User
// Appeler une fonction async
Task
// async let — exécution parallèle
async let user1 = fetchUser(id: 1)
async let user2 = fetchUser(id: 2)
let users = try await [user1, user2] // Parallèle !
// TaskGroup — nombre dynamique de tâches
let results = try await withThrowingTaskGroup(of: User.self)
actor Counter
let counter = Counter()
await counter.increment() // await obligatoire (isolation)
let val = await counter.value()
// @MainActor — exécuter sur le thread principal (UI)
@MainActor
func updateUI()
Les Actors éliminent les data races comme Rust, mais au runtime plutôt qu'à la compilation. L'accès aux propriétés d'un actor nécessite await, garantissant l'exclusion mutuelle.
Protocols et bonnes pratiques
protocol Describable
// Extension de protocol — implémentation par défaut
extension Describable
// Conformer (struct ou class)
struct Book: Describable
// Composition de protocols
protocol Identifiable
func display(_ item: Describable & Identifiable)
// Protocols standard importants
// Equatable → ==
// Comparable → < >
// Hashable → clé de Dictionary/Set
// Codable → JSON encode/decode
// CustomStringConvertible → print()
// Identifiable → SwiftUI lists
Protocol-Oriented Programming (POP) est le paradigme préféré de Swift. Plutôt que l'héritage de classes, on compose des behaviours avec des protocols + extensions. C'est plus flexible, testable et fonctionne avec les structs.
struct User: Codable
// Encode (Swift → JSON)
let user = User(name: « Alice », email: « alice@mail.com », age: 25)
let json = try JSONEncoder().encode(user)
// Decode (JSON → Swift)
let decoded = try JSONDecoder().decode(User.self, from: json)
✅ À FAIRE
• let par défaut (immutabilité)
• struct par défaut (value type)
• guard let pour l'early exit
• Codable pour le JSON
• ?? au lieu de force unwrap
• Protocol-oriented (POP)
• async/await pour la concurrence
• Extensions pour organiser le code
• Access control (private, fileprivate)
❌ À ÉVITER
• ! force unwrap en production
• var quand let suffit
• Classes quand struct suffit
• Héritage profond (préférer protocols)
• Massive View Controllers (MVVM)
• Any / AnyObject abusif
• Retain cycles (weak/unowned)
• Ignorer les warnings Xcode
• Singletons excessifs
class Person
class Pet
// Dans les closures — capture list
class ViewModel
🏠 Hub Programmation
🐍 Cours Python
⚡ Cours JavaScript
🔷 Cours TypeScript
☁️ AWS Cloud Practitioner
Cours Swift Complet — Optionals, Protocols et l'écosystème Apple
Référence : The Swift Book | Apple Developer
