Conteneur d'injection de dépendances pour Swift (iOS/macOS) : Swinject
Dans le développement moderne iOS et macOS avec Swift, les patrons architecturaux jouent un rôle clé dans la création d'un code maintenable et testable. L'un des outils les plus puissants pour implémenter le principe d'inversion des dépendances (Dependency Inversion Principle) est Swinject — un conteneur DI léger mais fonctionnel, écrit en Swift. Swinject permet de gérer de manière centralisée la création d'objets et leurs dépendances, libérant le développeur de la construction manuelle du graphe d'objets.
Qu'est-ce que l'injection de dépendances et pourquoi un conteneur ?
L'injection de dépendances (DI) est une technique par laquelle un objet reçoit ses dépendances de l'extérieur, plutôt que de les créer lui-même. Cela réduit le couplage du code et simplifie les tests unitaires. Cependant, dans les grands projets, l'injection manuelle des dépendances conduit à un code volumineux. C'est là qu'un conteneur DI intervient, qui :
- Automatise la création et la liaison des objets
- Gère la durée de vie des objets (singletons, nouvelles instances)
- Facilite le remplacement des implémentations (par exemple, pour les tests)
- Améliore la lisibilité et la maintenabilité du code
Installation de Swinject
Swinject peut être installé via Swift Package Manager, CocoaPods ou Carthage. Pour SPM, ajoutez dans Package.swift :
dependencies: [ .package(url: "https://github.com/Swinject/Swinject.git", from: "2.8.0")]Ou via CocoaPods :
pod 'Swinject', '~> 2.8'Concepts clés de Swinject
La bibliothèque repose sur plusieurs composants essentiels :
- Container — l'enregistreur et résolveur principal des dépendances
- Service — le type qui est enregistré (généralement un protocole ou une classe)
- Component — l'implémentation concrète du service
- Scope — détermine la durée de vie de l'objet (transient, graph, container, weak)
Exemple pratique : enregistrement et résolution des dépendances
Considérons un scénario typique — une application avec un service d'authentification et un contrôleur qui l'utilise.
// Protocole du serviceprotocol AuthServiceProtocol { func login(username: String, password: String) -> Bool}
// Implémentationclass AuthService: AuthServiceProtocol { func login(username: String, password: String) -> Bool { // Logique d'authentification return username == "admin" && password == "1234" }}
// Contrôleur dépendant de AuthServiceProtocolclass LoginViewController { private let authService: AuthServiceProtocol // Injection via l'initialiseur init(authService: AuthServiceProtocol) { self.authService = authService } func authenticate(user: String, pass: String) { if authService.login(username: user, password: pass) { print("Connexion réussie") } else { print("Données incorrectes") } }}
// Configuration du conteneurlet container = Container()container.register(AuthServiceProtocol.self) { _ in AuthService() }container.register(LoginViewController.self) { r in LoginViewController(authService: r.resolve(AuthServiceProtocol.self)!)}
// Utilisationlet controller = container.resolve(LoginViewController.self)!controller.authenticate(user: "admin", pass: "1234") // Connexion réussieGestion de la durée de vie (Scopes)
Swinject prend en charge quatre scopes intégrés :
- .transient — une nouvelle instance est créée à chaque fois (par défaut)
- .graph — une instance par graphe de résolution (utilisé par défaut dans la plupart des cas)
- .container — singleton dans le cadre du conteneur
- .weak — référence faible, l'objet
Aussi dans la bibliothèque
Polars pour Rust : guide complet avec exemples
Génération de PDF en C# (.NET) : meilleures bibliothèques et exemples de code
Travail avec les dates en Java : aperçu des bibliothèques java.time, Joda-Time et Apache Commons
Travailler avec les jetons JWT en TypeScript : bibliothèque jsonwebtoken et guide complet
Génération Swagger/OpenAPI pour Go (Golang) : guide complet