Swinject: co to jest, zasady Dependency Injection i jak działa

Autor: IT Sectr Opublikowano: 2026-05-04 Czas czytania: 8 min

Swinject — to kontener DI dla Swift, implementujący wzorzec Dependency Injection w aplikacjach iOS. Framework automatyzuje tworzenie i wstrzykiwanie zależności, eliminując ręczne zarządzanie obiektami i fabrykami. Według danych Swinject na GitHub, biblioteka obsługuje Constructor Injection, Property Injection i Method Injection z elastycznym systemem zakresów do zarządzania czasem życia.

Najważniejsze

  • Swinject — kontener DI dla Swift, automatyzujący wstrzykiwanie zależności w projektach iOS.
  • Dependency Injection — wzorzec, w którym obiekt otrzymuje zależności z zewnątrz, zamiast tworzyć je wewnątrz siebie.
  • Container — centralny komponent Swinject, przechowujący rejestr zarejestrowanych serwisów i ich fabryk.
  • Service — abstrakcja w postaci protokołu, dla której kontener przechowuje konkretną implementację.
  • ObjectScope — mechanizm określający czas życia instancji: graph, container lub transient.

Czym jest Swinject i Dependency Injection

Swinject — to otwarty kontener DI dla języka Swift, zaprojektowany do uproszczenia wstrzykiwania zależności w aplikacjach na iOS, macOS i watchOS. Framework wykorzystuje podejście Service Locator: serwisy rejestrowane są w centralnym kontenerze, a kontener automatycznie rozpoznaje graf zależności przy żądaniu instancji.

Dependency Injection (DI) — wzorzec projektowy, w którym obiekt otrzymuje swoje zależności z zewnątrz, zamiast tworzyć je wewnątrz. Zmniejsza to powiązanie między komponentami, upraszcza testowanie modułowe i umożliwia wymianę implementacji bez zmiany kodu konsumenta.

Według Martina Fowlera (2004), DI jest szczególnym przypadkiem Inversion of Control i jest realizowane przez wstrzykiwanie przez konstruktor, właściwość lub metodę. Swinject automatyzuje ten proces, eliminując ręczne pisanie fabryk i lokalizatorów serwisów.

Stosuj Swinject w projektach z trzema lub więcej serwisami mającymi zależności krzyżowe, gdzie ręczne konstruowanie obiektów prowadzi do rozrostu kodu inicjalizacyjnego i obniżenia testowalności.

Swinject ściśle integruje się z ekosystemem Apple i obsługuje wszystkie wersje Swift począwszy od 3.0. Framework jest kompatybilny z Objective-C przez mosty, co pozwala wdrażać go w istniejących projektach napisanych w mieszanym języku bez pełnej migracji kodu. Jest to szczególnie istotne w dużych aplikacjach z historią rozwoju przekraczającą pięć lat.

Jak działa kontener Swinject

Kontener Swinject jest zaimplementowany przez klasę Container, która przechowuje rejestr zarejestrowanych serwisów. Przy wywołaniu metody resolve kontener tworzy obiekt, rozwiązując wszystkie jego zależności rekurencyjnie według grafu rejestracji.

Container i Service

Container — centralny obiekt, w którym rejestrowane są odpowiedniki między abstrakcją a jej implementacją. Service — protokół określający kontrakt, a Component — klasa implementująca ten protokół. Rejestracja wykonywana jest metodą register, przyjmującą typ serwisu i fabrykę.

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

Metoda resolve zwraca instancję konkretnej implementacji zarejestrowanej dla określonego protokołu. Jeśli zależność nie jest zarejestrowana, kontener zgłasza błąd krytyczny w celu szybkiego wykrycia problemu na etapie rozwoju.

Registration i nazwane serwisy

Każda rejestracja tworzy wpis z funkcją fabryki i wybranym zakresem. Jeden serwis może mieć wiele rejestracji z różnymi nazwami, co pozwala wybrać konkretną implementację po nazwie — przydatne dla różnych środowisk (developerskie, stagingowe, produkcyjne).

Proces rozwiązywania zależności (resolution) działa rekurencyjnie: gdy kontener tworzy instancję Component, analizuje jej inicjalizator i dla każdego parametru wywołuje resolve odpowiedniego typu. Jeśli zależność również ma swoje zależności, proces trwa aż cały graf zostanie w pełni zbudowany. Głębokość zagnieżdżenia jest ograniczona tylko dostępną pamięcią, ale w praktyce rzadko przekracza pięć poziomów.

Sposoby wstrzykiwania zależności w Swinject

Swinject obsługuje trzy główne sposoby wstrzykiwania zależności, z których każdy ma zastosowanie w zależności od kontekstu architektonicznego.

Constructor Injection

Constructor Injection — wstrzykiwanie zależności przez parametry inicjalizatora. Jest to preferowany sposób, gwarantujący, że obiekt zawsze znajduje się w poprawnym stanie od momentu utworzenia. Swinject automatycznie rozwiązuje wszystkie zależności przekazane do konstruktora.

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 — wstrzykiwanie przez ustawienie właściwości obiektu po jego inicjalizacji. Stosowane, gdy zależność jest opcjonalna lub nie może być przekazana przez konstruktor, na przykład podczas pracy ze Storyboard, gdzie kontroler widoku jest tworzony automatycznie. Swinject obsługuje adnotację @Inject do automatycznego wstrzykiwania właściwości przez runtime bez jawnego wywoływania resolve.

Przy użyciu Property Injection ważne jest, aby upewnić się, że zależność została ustawiona przed pierwszym dostępem do obiektu. W przeciwnym razie właściwość pozostanie nil, co doprowadzi do nieoczekiwanego crasha. Swinject rozwiązuje ten problem przez mechanizm Implicitly Unwrapped Optional i ścisłą weryfikację na etapie rozwiązywania grafu zależności.

Method Injection

Method Injection — wstrzykiwanie przez parametry metody. Stosowane dla serwisów, które są potrzebne tylko do wykonania jednej operacji i nie powinny być przechowywane jako stały stan obiektu. Jest to najmniej rozpowszechniony, ale przydatny dla callbacków sposób wstrzykiwania.

Zakresy w Swinject i ich przeznaczenie

ObjectScope — mechanizm określający czas życia tworzonej instancji wewnątrz kontenera Swinject. Framework udostępnia trzy wbudowane zakresy z możliwością tworzenia niestandardowych przez protokół ObjectScopeProtocol.

ObjectScope.graph

Zakres graph — wartość domyślna. Przy każdym wywołaniu resolve tworzona jest nowa instancja, która żyje tylko na czas rozwiązywania grafu zależności. Jest to bezpieczny wybór dla serwisów bezstanowych, ponieważ eliminuje wycieki pamięci spowodowane buforowaniem.

ObjectScope.container

Zakres container — singleton w ramach kontenera. Instancja tworzona jest raz przy pierwszym resolve i zwracana przy wszystkich kolejnych żądaniach. Nadaje się do serwisów ze wspólnym stanem: cache danych, logger, ustawienia aplikacji.

ObjectScope.transient

Zakres transient — każde wywołanie resolve tworzy nową instancję bez buforowania. Stosowane dla lekkich obiektów, których nie trzeba ponownie używać — na przykład dla modułów obsługi konkretnego żądania HTTP.

ZakresCzas życiaZalecane zastosowanie
graphNa czas rozwiązywania grafuSerwisy bezstanowe domyślnie
containerCały czas życia konteneraSingleton: cache, logger, klient sieciowy
transientBez buforowaniaLekkie obiekty do jednorazowego użytku

Swinject w projektach iOS

Integracja Swinject w rzeczywistym projekcie iOS zaczyna się od inicjalizacji kontenera na starcie aplikacji — w AppDelegate lub scenie. Zaleca się strukturyzację rejestracji przez Assembly: oddzielna klasa lub struktura grupująca powiązane serwisy.

Według danych ankiety Swift Developer Community (2025), 43% programistów iOS używa kontenerów DI w komercyjnych projektach do zarządzania zależnościami warstwy sieciowej, repozytoriów i koordynatorów nawigacji. Swinject pozostaje najpopularniejszym rozwiązaniem dzięki minimalnej składni i kompatybilności z Objective-C.

Storyboard Injection — unikalna możliwość Swinject: kontener automatycznie wstrzykuje zależności do kontrolerów widoku tworzonych ze Storyboard, bez dodatkowego kodu w AppDelegate. W tym celu używany jest specjalny resolver przekazywany do UIStoryboard przez metodę init(container:), który przechwytuje tworzenie kontrolera widoku i wstrzykuje zarejestrowane zależności.

W dużych projektach Swinject można łączyć z koordynatorami nawigacji: koordynator otrzymuje kontener i tworzy ekrany, rozwiązując ich zależności przez resolve, co zachowuje jeden punkt konfiguracji dla całej sceny.

Architektura z Assembly — zalecany wzorzec do organizacji rejestracji. Każdy Assembly grupuje powiązane serwisy (np. NetworkingAssembly, DatabaseAssembly) i może zależeć od innych Assemblyów. Podczas inicjalizacji kontenera wszystkie Assembly ładują się i rejestrują swoje serwisy, co zapewnia wyraźny podział odpowiedzialności i upraszcza nawigację po konfiguracji DI w dużych projektach z dziesiątkami serwisów.

Do debugowania grafu DI Swinject udostępnia rozszerzenie SwinjectPropertyLoader, które ładuje konfigurację z pliku plist, oraz SwinjectStoryboard — integrację ze storyboardami przez specjalną wersję UIStoryboard. Te narzędzia są szczególnie przydatne na etapie przenoszenia istniejącego projektu z ręcznego konstruowania obiektów na DI: programista może stopniowo rejestrować serwisy, sprawdzając graf zależności przez testy i logowanie błędów rozwiązywania, nie wstrzymując rozwoju głównych funkcji aplikacji.

Swinject zapewnia również integrację z RxSwift i Combine przez rozszerzenie SwinjectAutoregistration do automatycznego rozwiązywania zależności według typów parametrów inicjalizatora bez jawnej rejestracji fabryk. Zmniejsza to ilość kodu rejestracyjnego dla prostych serwisów: wystarczy wywołać container.register(ServiceProtocol.self) bez podawania fabryki, a Swinject samodzielnie zbuduje fabrykę na podstawie refleksji Signal dostarczanej przez środowisko wykonawcze Swift. To podejście jest zalecane dla serwisów, których konstruktor przyjmuje tylko typy podstawowe i nie wymaga złożonej logiki przy tworzeniu.

Często zadawane pytania

Czym Swinject różni się od innych frameworków DI dla Swift?

Swinject jest napisany w czystym Swift bez generowania kodu i refleksji. W przeciwieństwie do Needle, nie wymaga generowania źródeł, a w porównaniu z Dip — zapewnia wbudowane wsparcie dla Storyboard Injection, co upraszcza integrację z istniejącymi projektami UIKit.

Jak zainstalować Swinject przez Swift Package Manager?

Dodaj pakiet pod adresem URL github.com/Swinject/Swinject przez Xcode w menu File — Add Packages. Dostępna jest również instalacja przez CocoaPods i Carthage. Po instalacji zaimportuj moduł Swinject i utwórz instancję Container.

Czy można używać Swinject w projektach SwiftUI?

Tak, Swinject jest w pełni kompatybilny ze SwiftUI. Zależności są wstrzykiwane przez inicjalizatory View lub przez Environment, gdzie kontener jest przekazywany jako EnvironmentObject. Swinject nie zależy od UIKit i działa tak samo z oboma frameworkami.

Jak stosować Swinject do testowania modułowego?

Utwórz osobny kontener dla testów, zastępując rzeczywiste serwisy makietami. Swinject pozwala nadpisywać rejestracje bez zmiany kodu konsumentów. Każdy test otrzymuje izolowany kontener z minimalnym zestawem zależności.

Jaki zakres wybrać dla serwisu analityki?

Dla analityki używaj zakresu container, aby wszystkie ekrany wysyłały zdarzenia przez jedną instancję. Gwarantuje to jednolitą kolejkę wysyłania i poprawną agregację wsadową bez duplikowania danych między różnymi konsumentami.

Podsumowanie

  • Swinject — kontener DI dla Swift, automatyzujący wstrzykiwanie zależności przez Container i ObjectScope.
  • Dependency Injection zmniejsza powiązanie kodu, upraszcza testowanie i umożliwia wymianę implementacji bez zmiany konsumentów.
  • Container — rejestr serwisów obsługujący register do rejestracji i resolve do pobierania instancji.
  • Constructor Injection — preferowany sposób wstrzykiwania, gwarantujący poprawny stan obiektu.
  • ObjectScope zarządza czasem życia: graph (domyślnie), container (singleton) i transient (bez cache).
  • Storyboard Injection automatycznie wstrzykuje zależności w sceny UIKit bez ręcznej konfiguracji.
  • Do testów modułowych używaj osobnego kontenera z makietami serwisów.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również