Comment réussir un entretien Swift : niveau avancé
\n\nUn entretien pour un poste de développeur iOS Senior ou de Team Lead ne se limite pas à une simple vérification de la connaissance de la syntaxe. Les recruteurs veulent voir une compréhension approfondie du fonctionnement interne de Swift, la capacité à concevoir une architecture et à éviter les pièges courants. Dans cet article, nous allons analyser 4 blocs de questions de niveau avancé, souvent posés lors des entretiens. Chaque bloc est accompagné d'exemples de code et d'explications pour vous aider à répondre avec confiance à n'importe quelle question.
\n\n1. Automatic Reference Counting (ARC) et gestion de la mémoire
\n\nL'ARC est un sujet clé. Le recruteur peut vous interroger sur les cycles de références fortes (strong reference cycles) et les moyens de les briser.
Question : Qu'est-ce qu'une capture list et comment aide-t-elle à éviter un retain cycle dans les closures ?
\n\nLes closures en Swift sont des types par référence. Si une closure capture self (par exemple, une propriété de classe), et que l'objet lui-même stocke cette closure, un cycle se crée. La solution est d'utiliser une capture list avec les modificateurs [weak self] ou [unowned self].
class NetworkManager {\n var onComplete: (() -> Void)?\n\n func fetchData() {\n // DANGEREUX : capture de référence forte\n onComplete = {\n self.processData() // retain cycle !\n }\n\n // CORRECT : capture faible\n onComplete = { [weak self] in\n guard let self = self else { return }\n self.processData()\n }\n }\n\n func processData() { print("Processing...") }\n deinit { print("NetworkManager deallocated") }\n}\n\nImportant : utilisez unowned self uniquement si vous êtes sûr que l'objet sera vivant au moment de l'appel de la closure. Sinon, utilisez weak self.
2. Generics et protocoles avec associatedtype
\n\nLe niveau avancé implique la capacité à écrire du code générique et à comprendre les limitations des protocoles avec types associés.
\n\nQuestion : Quelle est la différence entre un protocole avec associatedtype et un protocole avec generics ? Comment utiliser les Opaque Types (some) ?
\n\nUn protocole avec associatedtype ne peut pas être utilisé comme un type autonome. Pour masquer le type concret, on utilise le mot-clé some (opaque return type), apparu dans Swift 5.1.
// Protocole avec type associé\nprotocol Container {\n associatedtype Item\n mutating func append(_ item: Item)\n var count: Int { get }\n}\n\n// Implémentation\nstruct IntBox: Container {\n typealias Item = Int\n private var items: [Int] = []\n mutating func append(_ item: Int) { items.append(item) }\n var count: Int { items.count }\n}\n\n// La fonction retourne "some Container" — le type concret est masqué\nfunc makeContainer() -> some Container {\n return IntBox()\n}\n\n// Utilisation\nvar box = makeContainer()\nbox.append(42)\nprint(box.count) // 1\n\nCette approche permet de changer l'implémentation de manière flexible sans modifier le code appelant. C'est souvent demandé dans le contexte de SwiftUI et du pattern Builder.
\n\n3. Multithreading : GCD et OperationQueue
\n\nLa connaissance de Grand Central Dispatch et des opérations est un point obligatoire pour tout développeur iOS. Les questions avancées concernent les deadlocks, la thread safety et les priorités.
\n\nQuestion : Comment éviter une Data Race lors du travail avec des données partagées depuis différents threads ?
\n\nUne Data Race se produit lorsque deux threads lisent et écrivent simultanément dans la même zone mémoire sans synchronisation. La solution consiste à utiliser une file d'attente sérialisée ou un verrou.
\n\nclass ThreadSafeCounter {\n private var count = 0\n // File d'attente sérialisée pour la synchronisation\n private let queue = DispatchQueue(label: "com.example.counter")\n\n func increment() {\n queue.sync {\n count += 1\n }\n }\n\n func getCount() -> Int {\n return queue.sync