Swinject : ce que c'est, principes de Dependency Injection et fonctionnement

Auteur : IT Sectr Publié le : 2026-05-04 Temps de lecture : 8 min

Swinject est un conteneur DI pour Swift qui implémente le modèle Dependency Injection dans les applications iOS. Le framework automatise la création et l'injection de dépendances, éliminant la gestion manuelle des objets et des fabriques. Selon Swinject sur GitHub, la bibliothèque prend en charge Constructor Injection, Property Injection et Method Injection avec un système flexible de scopes pour la gestion de la durée de vie.

Points clés

  • Swinject — un conteneur DI pour Swift qui automatise l'injection de dépendances dans les projets iOS.
  • Dependency Injection — un modèle où un objet reçoit ses dépendances de l'extérieur plutôt que de les créer en interne.
  • Container — le composant central de Swinject qui stocke un registre des services enregistrés et de leurs fabriques.
  • Service — une abstraction sous forme de protocole pour laquelle le conteneur stocke une implémentation concrète.
  • ObjectScope — un mécanisme qui détermine la durée de vie de l'instance : graph, container ou transient.

Qu'est-ce que Swinject et Dependency Injection

Swinject est un conteneur DI open source pour le langage Swift, conçu pour simplifier l'injection de dépendances dans les applications pour iOS, macOS et watchOS. Le framework utilise l'approche Service Locator : les services sont enregistrés dans un conteneur central, et le conteneur résout automatiquement le graphe de dépendances lorsqu'une instance est demandée.

Dependency Injection (DI) est un modèle de conception où un objet reçoit ses dépendances de l'extérieur plutôt que de les créer en interne. Cela réduit le couplage entre les composants, simplifie les tests unitaires et permet de remplacer les implémentations sans modifier le code du consommateur.

Selon Martin Fowler (2004), DI est un cas spécifique d'Inversion of Control et est implémenté par injection via le constructeur, la propriété ou la méthode. Swinject automatise ce processus, éliminant la nécessité d'écrire manuellement des fabriques et des localisateurs de services.

Utilisez Swinject dans des projets avec trois services ou plus ayant des dépendances croisées, où la construction manuelle d'objets entraîne un gonflement du code d'initialisation et une réduction de la testabilité.

Swinject s'intègre étroitement avec l'écosystème Apple et prend en charge toutes les versions de Swift à partir de 3.0. Le framework est compatible avec Objective-C via des ponts, permettant son introduction dans des projets existants en langage mixte sans migration complète du code. C'est particulièrement pertinent pour les grandes applications avec plus de cinq ans de développement.

Comment fonctionne le conteneur Swinject

Le conteneur Swinject est implémenté par la classe Container, qui stocke un registre des services enregistrés. Lorsque la méthode resolve est appelée, le conteneur crée un objet, résolvant récursivement toutes ses dépendances à travers le graphe d'enregistrement.

Container et Service

Container est l'objet central où les correspondances entre les abstractions et leurs implémentations sont enregistrées. Un Service est un protocole qui définit un contrat, tandis qu'un Component est une classe qui implémente ce protocole. L'enregistrement se fait à l'aide de la méthode register, qui prend le type de service et une fabrique.

swift
let container = Container()
container.register(Networking.self) { _ in
    NetworkService()
}
let service = container.resolve(Networking.self)

La méthode resolve retourne une instance de l'implémentation concrète enregistrée pour le protocole spécifié. Si une dépendance n'est pas enregistrée, le conteneur lève une erreur fatale pour une détection rapide du problème pendant le développement.

Enregistrement et services nommés

Chaque enregistrement crée une entrée avec une fonction de fabrique et un scope sélectionné. Un même service peut avoir plusieurs enregistrements avec des noms différents, permettant de sélectionner une implémentation spécifique par nom — utile pour différents environnements (développement, staging, production).

Le processus de résolution des dépendances fonctionne récursivement : lorsque le conteneur crée une instance de Component, il analyse son initialiseur et pour chaque paramètre appelle resolve avec le type correspondant. Si une dépendance a également ses propres dépendances, le processus se poursuit jusqu'à ce que l'ensemble du graphe soit entièrement construit. La profondeur d'imbrication est limitée uniquement par la mémoire disponible, mais dépasse rarement cinq niveaux en pratique.

Méthodes d'injection de dépendances dans Swinject

Swinject prend en charge trois méthodes principales d'injection de dépendances, chacune applicable selon le contexte architectural.

Constructor Injection

Constructor Injection injecte les dépendances via les paramètres de l'initialiseur. C'est la méthode préférée, garantissant qu'un objet est toujours dans un état valide dès sa création. Swinject résout automatiquement toutes les dépendances passées au constructeur.

swift
class LoginViewModel {
    private let authService: AuthProtocol

    init(authService: AuthProtocol) {
        self.authService = authService
    }
}

container.register(AuthProtocol.self) { _ in
    AuthService()
}
container.register(LoginViewModel.self) { r in
    LoginViewModel(authService: r.resolve(AuthProtocol.self)!)
}

Property Injection

Property Injection injecte les dépendances en définissant les propriétés de l'objet après l'initialisation. Elle est utilisée lorsqu'une dépendance est optionnelle ou ne peut pas être transmise via le constructeur, par exemple, lors du travail avec Storyboard, où le view controller est créé automatiquement. Swinject prend en charge l'annotation @Inject pour l'injection automatique de propriétés à l'exécution sans appel explicite à resolve.

Lors de l'utilisation de Property Injection, il est important de s'assurer que la dépendance est définie avant le premier accès à l'objet. Sinon, la propriété restera nil, entraînant un crash inattendu. Swinject résout ce problème grâce au mécanisme Implicitly Unwrapped Optional et à une validation stricte à l'étape de résolution du graphe de dépendances.

Method Injection

Method Injection injecte les dépendances via les paramètres de méthode. Elle est utilisée pour les services qui ne sont nécessaires que pour effectuer une seule opération et ne doivent pas être stockés comme état permanent de l'objet. C'est la méthode d'injection la moins courante mais utile pour les callbacks.

Scopes dans Swinject et leur objectif

ObjectScope est un mécanisme qui détermine la durée de vie d'une instance créée à l'intérieur du conteneur Swinject. Le framework fournit trois scopes intégrés avec la possibilité d'en créer des personnalisés via ObjectScopeProtocol.

ObjectScope.graph

Le scope graph est la valeur par défaut. Chaque appel à resolve crée une nouvelle instance qui vit seulement pendant la durée de la résolution du graphe de dépendances. C'est un choix sûr pour les services sans état car il élimine les fuites de mémoire dues à la mise en cache.

ObjectScope.container

Le scope container est un singleton au sein du conteneur. L'instance est créée une fois au premier resolve et retournée pour toutes les demandes suivantes. Convient aux services avec état partagé : cache de données, logger, paramètres de l'application.

ObjectScope.transient

Le scope transient crée une nouvelle instance à chaque appel à resolve sans mise en cache. Utilisé pour les objets légers qui n'ont pas besoin d'être réutilisés — par exemple, les modules traitant une requête HTTP spécifique.

ScopeDurée de vieUtilisation recommandée
graphPendant la résolution du grapheServices sans état par défaut
containerToute la vie du conteneurSingletons : cache, logger, client réseau
transientSans mise en cacheObjets légers à usage unique

Swinject dans les projets iOS

L'intégration de Swinject dans un projet iOS réel commence par l'initialisation du conteneur au lancement de l'application — dans AppDelegate ou la scène. Il est recommandé de structurer les enregistrements via Assembly : une classe ou structure séparée qui regroupe les services associés.

Selon une enquête de la Swift Developer Community (2025), 43% des développeurs iOS utilisent des conteneurs DI dans des projets commerciaux pour gérer les dépendances de la couche réseau, des repositories et des coordinateurs de navigation. Swinject reste la solution la plus populaire grâce à sa syntaxe minimale et sa compatibilité avec Objective-C.

Storyboard Injection est une fonctionnalité unique de Swinject : le conteneur injecte automatiquement les dépendances dans les view controllers créés à partir de Storyboard sans code supplémentaire dans AppDelegate. Cela utilise un résolveur spécial passé à UIStoryboard via la méthode init(container:), qui intercepte la création du view controller et injecte les dépendances enregistrées.

Dans les grands projets, Swinject peut être combiné avec des coordinateurs de navigation : le coordinateur reçoit le conteneur et crée des écrans en résolvant leurs dépendances via resolve, maintenant un point de configuration unique pour toute la scène.

L'architecture Assembly est le modèle recommandé pour organiser les enregistrements. Chaque Assembly regroupe des services associés (par exemple, NetworkingAssembly, DatabaseAssembly) et peut dépendre d'autres Assemblies. Lors de l'initialisation du conteneur, tous les Assemblies sont chargés et enregistrent leurs services, offrant une séparation claire des responsabilités et simplifiant la navigation dans la configuration DI dans les grands projets avec des dizaines de services.

Pour le débogage du graphe DI, Swinject fournit l'extension SwinjectPropertyLoader, qui charge la configuration à partir d'un fichier plist, et SwinjectStoryboard — l'intégration avec les storyboards via une version spéciale d'UIStoryboard. Ces outils sont particulièrement utiles lors de la migration d'un projet existant de la construction manuelle d'objets vers DI : le développeur peut enregistrer progressivement des services, en vérifiant le graphe de dépendances via des tests et la journalisation des erreurs de résolution sans arrêter le développement des fonctionnalités principales.

Swinject offre également une intégration avec RxSwift et Combine via l'extension SwinjectAutoregistration pour la résolution automatique des dépendances basée sur les types de paramètres de l'initialiseur sans enregistrement explicite de fabrique. Cela réduit la quantité de code d'enregistrement pour les services simples : il suffit d'appeler container.register(ServiceProtocol.self) sans spécifier de fabrique, et Swinject construira automatiquement la fabrique sur la base de la réflexion Signal fournie par l'environnement d'exécution Swift. Cette approche est recommandée pour les services dont les constructeurs acceptent uniquement des types de base et ne nécessitent pas de logique de création complexe.

Foire aux questions

En quoi Swinject diffère-t-il des autres frameworks DI pour Swift ?

Swinject est écrit en Swift pur sans génération de code ni réflexion. Contrairement à Needle, il ne nécessite pas de génération de sources, et par rapport à Dip, il offre une prise en charge intégrée de Storyboard Injection, simplifiant l'intégration dans les projets UIKit existants.

Comment installer Swinject via Swift Package Manager ?

Ajoutez le paquet via l'URL github.com/Swinject/Swinject dans Xcode via le menu File — Add Packages. L'installation via CocoaPods et Carthage est également disponible. Après l'installation, importez le module Swinject et créez une instance de Container.

Peut-on utiliser Swinject dans les projets SwiftUI ?

Oui, Swinject est entièrement compatible avec SwiftUI. Les dépendances sont injectées via les initialiseurs de View ou via Environment, où le conteneur est passé comme EnvironmentObject. Swinject ne dépend pas d'UIKit et fonctionne aussi bien avec les deux frameworks.

Comment utiliser Swinject pour les tests unitaires ?

Créez un conteneur séparé pour les tests, en remplaçant les services réels par des mocks. Swinject permet de remplacer les enregistrements sans modifier le code des consommateurs. Chaque test reçoit un conteneur isolé avec un ensemble minimal de dépendances.

Quel scope choisir pour un service d'analyse ?

Pour les analyses, utilisez le scope container afin que tous les écrans envoient des événements via une seule instance. Cela garantit une file d'envoi unifiée et un fonctionnement correct de l'agrégation par lots sans duplication de données entre différents consommateurs.

Résumé

  • Swinject — un conteneur DI pour Swift qui automatise l'injection de dépendances via Container et ObjectScope.
  • Dependency Injection réduit le couplage du code, simplifie les tests et permet de remplacer les implémentations sans modifier les consommateurs.
  • Container — un registre de services prenant en charge register pour l'enregistrement et resolve pour la récupération d'instances.
  • Constructor Injection est la méthode d'injection préférée, garantissant l'état valide de l'objet.
  • ObjectScope gère la durée de vie : graph (par défaut), container (singleton) et transient (sans cache).
  • Storyboard Injection injecte automatiquement les dépendances dans les scènes UIKit sans configuration manuelle.
  • Pour les tests unitaires, utilisez un conteneur séparé avec des implémentations mock des services.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi