Dependency Injection Container Swift: Swinject für iOS/macOS

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Dependency Injection Container für Swift (iOS/macOS): Swinject

In der modernen iOS- und macOS-Entwicklung mit Swift spielen Architekturmuster eine Schlüsselrolle bei der Erstellung von wartbarem und testbarem Code. Eines der leistungsstärksten Werkzeuge zur Umsetzung des Dependency Inversion Principle ist Swinject – ein leichter, aber funktionaler DI-Container, der in Swift geschrieben ist. Swinject ermöglicht die zentrale Verwaltung der Objekterstellung und deren Abhängigkeiten und befreit den Entwickler von der manuellen Konstruktion des Objektgraphen.



Was ist Dependency Injection und wozu braucht man einen Container?

Dependency Injection (DI) ist eine Technik, bei der ein Objekt seine Abhängigkeiten von außen erhält, anstatt sie selbst zu erstellen. Dies reduziert die Kopplung des Codes und vereinfacht das Modultesten. In großen Projekten führt die manuelle Abhängigkeitsinjektion jedoch zu umfangreichem Code. Hier kommt der DI-Container ins Spiel, der:

  • Die Erstellung und Verknüpfung von Objekten automatisiert
  • Die Lebensdauer von Objekten verwaltet (Singletons, neue Instanzen)
  • Den Austausch von Implementierungen vereinfacht (z. B. für Tests)
  • Die Lesbarkeit und Wartbarkeit des Codes erhöht


Installation von Swinject

Swinject kann über Swift Package Manager, CocoaPods oder Carthage installiert werden. Für SPM fügen Sie in Package.swift hinzu:

dependencies: [    .package(url: "https://github.com/Swinject/Swinject.git", from: "2.8.0")]

Oder über CocoaPods:

pod 'Swinject', '~> 2.8'


Grundlegende Konzepte von Swinject

Die Bibliothek basiert auf mehreren Schlüsselkomponenten:

  • Container – der Hauptregistrator und -auflöser von Abhängigkeiten
  • Service – der Typ, der registriert wird (normalerweise ein Protokoll oder eine Klasse)
  • Component – die konkrete Implementierung des Dienstes
  • Scope – bestimmt die Lebensdauer des Objekts (transient, graph, container, weak)


Praktisches Beispiel: Registrierung und Auflösung von Abhängigkeiten

Betrachten wir ein typisches Szenario – eine App mit einem Authentifizierungsdienst und einem Controller, der diesen verwendet.

// Service-Protokollprotocol AuthServiceProtocol {    func login(username: String, password: String) -> Bool}

// Implementierungclass AuthService: AuthServiceProtocol { func login(username: String, password: String) -> Bool { // Authentifizierungslogik return username == "admin" && password == "1234" }}

// Controller, der von AuthServiceProtocol abhängtclass LoginViewController { private let authService: AuthServiceProtocol // Injektion über den Initialisierer init(authService: AuthServiceProtocol) { self.authService = authService } func authenticate(user: String, pass: String) { if authService.login(username: user, password: pass) { print("Erfolgreicher Login") } else { print("Ungültige Daten") } }}

// Container-Konfigurationlet container = Container()container.register(AuthServiceProtocol.self) { _ in AuthService() }container.register(LoginViewController.self) { r in LoginViewController(authService: r.resolve(AuthServiceProtocol.self)!)}

// Verwendunglet controller = container.resolve(LoginViewController.self)!controller.authenticate(user: "admin", pass: "1234") // Erfolgreicher Login


Verwaltung der Lebensdauer (Scopes)

Swinject unterstützt vier integrierte Scopes:

  • .transient – jedes Mal wird eine neue Instanz erstellt (Standard)
  • .graph – eine Instanz pro Auflösungsgraph (standardmäßig für die meisten Fälle verwendet)
  • .container – Singleton innerhalb des Containers
  • .weak – schwache Referenz, das Objekt

Empfehlungen