Injection de dépendances (Dependency Injection) en Swift : guide complet pour débutants

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : pourquoi votre code a-t-il besoin de l'injection de dépendances ?



Chaque développeur iOS rencontre la situation où une classe devient « lourde » et fortement liée à des implémentations spécifiques. Vous modifiez une classe et vous devez en réécrire des dizaines d'autres. Cela vous dit quelque chose ? C'est le problème classique du couplage fort (tight coupling).



L'injection de dépendances (Dependency Injection ou DI) est un modèle de conception qui résout ce problème. Au lieu que l'objet crée lui-même ses dépendances, celles-ci sont « injectées » de l'extérieur. Cela rend le code flexible, testable et conforme aux principes SOLID (en particulier le principe d'inversion des dépendances).



Dans cet article, nous allons voir ce qu'est la DI en Swift, quelles sont les différentes façons de l'implémenter, et comment elle simplifie la vie du développeur iOS/macOS. Nous utiliserons des exemples simples, compréhensibles même pour un débutant.



Qu'est-ce que l'injection de dépendances ? Un exemple simple



Imaginez que vous faites une pizza. Version sans DI : vous cultivez vous-même le blé, faites la farine, trayez la vache pour le fromage. C'est un couplage fort. Version avec DI : vous commandez simplement les ingrédients (dépendances) auprès d'un fournisseur. Vous ne savez pas comment la farine est fabriquée – seul le résultat compte.



En programmation, c'est la même chose. Supposons que nous ayons une classe OrderService qui envoie des commandes par email :



// ❌ Sans DI — couplage fortclass OrderService {    let mailer = Mailer() // Crée lui-même sa dépendance

func process(order: Order) { mailer.send(email: "Nouvelle commande : \\(order.id)") }}


Problème : nous ne pouvons pas remplacer Mailer par une version de test. La classe OrderService « en sait » trop.



// ✅ Avec DI — la dépendance est injectéeclass OrderService {    let mailer: MailerProtocol // Dépend de l'abstraction, pas du concret

init(mailer: MailerProtocol) { // Injection via l'initialiseur self.mailer = mailer }

func process(order: Order) { mailer.send(email: "Nouvelle commande : \\(order.id)") }}


Maintenant, nous pouvons passer n'importe quel objet conforme au protocole MailerProtocol — un service de messagerie réel ou une « maquette » pour les tests.



Les trois principales méthodes d'injection de dépendances en Swift



Il existe trois façons courantes de transmettre une dépendance à une classe. Examinons chacune d'elles.



1. Injection par constructeur (Constructor Injection)

La méthode la plus courante et préférée. La dépendance est transmise lors de la création de l'objet. Cela garantit que l'objet est toujours dans un état valide.



protocol NetworkServiceProtocol {    func fetchData() -> String}

class RealNetworkService: NetworkServiceProtocol { func fetchData() -> String { return "Données réelles du serveur" }}

class MockNetworkService: NetworkServiceProtocol { func fetchData() -> String { return "Données de test" }}

class DataManager { private let network: NetworkServiceProtocol

// La dépendance est transmise via init init(network: NetworkServiceProtocol) { self.network = network }

func load() -> String { return network.fetchData() }}

// Utilisationlet realManager = DataManager(network: RealNetworkService())let mockManager = DataManager(network: MockNetworkService())


Avantages : On voit clairement les dépendances nécessaires. L'objet est immédiatement prêt à fonctionner. Inconvénients : Si les dépendances sont nombreuses, l'initialiseur devient lourd.



2. Injection par propriété (Property Injection)

La dépendance est définie après la création de l'objet. Souvent utilisée lorsque la dépendance est optionnelle ou difficile à obtenir au moment de l'initialisation.



class UserViewModel {    var apiService: NetworkServiceProtocol? // Dépendance optionnelle

func loadUser() { apiServi

Blogs

Book Recommendations