Swinject je DI kontejner pro Swift, který implementuje vzor Dependency Injection v iOS aplikacích. Framework automatizuje vytváření a vkládání závislostí, čímž eliminuje ruční správu objektů a továren. Podle údajů Swinject na GitHubu knihovna podporuje Constructor Injection, Property Injection a Method Injection s flexibilním systémem scope pro správu životnosti.
Hlavní body
Swinject je open-source DI kontejner pro jazyk Swift, navržený ke zjednodušení vkládání závislostí v aplikacích pro iOS, macOS a watchOS. Framework využívá přístup Service Locator: služby jsou registrovány v centrálním kontejneru a kontejner automaticky řeší graf závislostí při požadavku na instanci.
Dependency Injection (DI) je návrhový vzor, při kterém objekt přijímá své závislosti zvenčí, místo aby je vytvářel uvnitř. To snižuje provázanost mezi komponentami, zjednodušuje modulární testování a umožňuje výměnu implementací bez změny kódu spotřebitele.
Podle Martina Fowlera (2004) je DI speciálním případem Inversion of Control a je realizována vkládáním přes konstruktor, vlastnost nebo metodu. Swinject tento proces automatizuje a eliminuje ruční psaní továren a lokátorů služeb.
Aplikujte Swinject v projektech se třemi nebo více službami s křížovými závislostmi, kde ruční konstrukce objektů vede k růstu inicializačního kódu a snížení testovatelnosti.
Swinject se úzce integruje s ekosystémem Apple a podporuje všechny verze Swiftu od 3.0 výše. Framework je kompatibilní s Objective-C přes mosty, což umožňuje jeho nasazení ve stávajících projektech napsaných ve smíšeném jazyce bez úplné migrace kódu. To je zvláště důležité pro velké aplikace s historií vývoje přesahující pět let.
Kontejner Swinject je implementován třídou Container, která uchovává registr registrovaných služeb. Při volání metody resolve kontejner vytvoří objekt a rekurzivně vyřeší všechny jeho závislosti podle registračního grafu.
Container je centrální objekt, ve kterém se registrují korespondence mezi abstrakcí a její implementací. Service je protokol definující smlouvu a Component je třída implementující tento protokol. Registrace se provádí metodou register, která přijímá typ služby a továrnu.
let container = Container()
container.register(Networking.self) { _ in
NetworkService()
}
let service = container.resolve(Networking.self)
Metoda resolve vrací instanci konkrétní implementace registrované pro daný protokol. Pokud závislost není registrována, kontejner vyhodí fatální chybu pro rychlé odhalení problému ve fázi vývoje.
Každá registrace vytváří záznam s tovární funkcí a vybraným scopen. Jedna služba může mít několik registrací s různými názvy, což umožňuje výběr konkrétní implementace podle názvu — užitečné pro různá prostředí (vývoj, staging, produkce).
Proces řešení závislostí (resolution) pracuje rekurzivně: když kontejner vytvoří instanci Component, analyzuje její inicializátor a pro každý parametr volá resolve odpovídajícího typu. Pokud má závislost také své vlastní závislosti, proces pokračuje, dokud není celý graf plně vytvořen. Hloubka vnoření je omezena pouze dostupnou pamětí, ale v praxi zřídka přesahuje pět úrovní.
Swinject podporuje tři hlavní způsoby vkládání závislostí, z nichž každý je použitelný v závislosti na architektonickém kontextu.
Constructor Injection — vkládání závislostí přes parametry inicializátoru. Toto je preferovaný způsob, který zaručuje, že objekt je vždy ve správném stavu od okamžiku vytvoření. Swinject automaticky řeší všechny závislosti předané konstruktoru.
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 — vkládání nastavením vlastností objektu po jeho inicializaci. Používá se, když je závislost volitelná nebo nelze předat konstruktorem, například při práci se Storyboard, kde je view controller vytvářen automaticky. Swinject podporuje anotaci @Inject pro automatické vkládání vlastností přes runtime bez explicitního volání resolve.
Při použití Property Injection je důležité zajistit, že závislost je nastavena před prvním přístupem k objektu. V opačném případě vlastnost zůstane nil, což povede k neočekávanému pádu. Swinject řeší tento problém mechanismem Implicitly Unwrapped Optional a přísnou kontrolou ve fázi řešení grafu závislostí.
Method Injection — vkládání přes parametry metody. Aplikuje se pro služby, které jsou potřeba pouze pro provedení jedné operace a neměly by být ukládány jako trvalý stav objektu. Toto je nejméně rozšířený, ale pro callbacky užitečný způsob vkládání.
ObjectScope — mechanismus určující životnost vytvořené instance uvnitř kontejneru Swinject. Framework poskytuje tři vestavěné scopy s možností vytváření vlastních scopes přes protokol ObjectScopeProtocol.
Scope graph — výchozí hodnota. Při každém volání resolve je vytvořena nová instance, která žije pouze po dobu řešení grafu závislostí. To je bezpečná volba pro služby bez stavu, protože eliminuje úniky paměti způsobené ukládáním do mezipaměti.
Scope container — singleton v rámci kontejneru. Instance je vytvořena jednou při prvním resolve a vracena při všech následujících požadavcích. Vhodné pro služby se sdíleným stavem: mezipaměť dat, logger, nastavení aplikace.
Scope transient — každé volání resolve vytváří novou instanci bez ukládání do mezipaměti. Používá se pro lehké objekty, které není třeba znovu používat — například pro moduly pracující s konkrétním HTTP požadavkem.
| Scope | Životnost | Doporučené použití |
|---|---|---|
| graph | Po dobu řešení grafu | Služby bez stavu ve výchozím nastavení |
| container | Celá životnost kontejneru | Singleton: mezipaměť, logger, síťový klient |
| transient | Bez ukládání do mezipaměti | Lehké objekty pro jednorázové použití |
Integrace Swinjectu do reálného iOS projektu začíná inicializací kontejneru při spuštění aplikace — v AppDelegate nebo scéně. Doporučuje se strukturovat registrace pomocí Assembly: samostatná třída nebo struktura seskupující související služby.
Podle průzkumu Swift Developer Community (2025) používá 43 % iOS vývojářů DI kontejnery v komerčních projektech pro správu závislostí síťové vrstvy, úložišť a navigačních koordinátorů. Swinject zůstává nejoblíbenějším řešením díky minimální syntaxi a kompatibilitě s Objective-C.
Storyboard Injection — jedinečná schopnost Swinjectu: kontejner automaticky vkládá závislosti do view controllerů vytvořených ze Storyboardu bez dalšího kódu v AppDelegate. K tomu se používá speciální resolver předávaný UIStoryboardu metodou init(container:), který zachycuje vytvoření view controlleru a vkládá registrované závislosti.
Ve velkých projektech lze Swinject kombinovat s navigačními koordinátory: koordinátor obdrží kontejner a vytváří obrazovky, řeší jejich závislosti přes resolve, čímž zachovává jediný konfigurační bod pro celou scénu.
Architektura s Assembly — doporučený vzor pro organizaci registrací. Každé Assembly seskupuje související služby (např. NetworkingAssembly, DatabaseAssembly) a může záviset na jiných Assembly. Při inicializaci kontejneru se všechna Assembly načtou a zaregistrují své služby, což poskytuje jasné oddělení odpovědnosti a zjednodušuje navigaci v DI konfiguraci ve velkých projektech s desítkami služeb.
Pro ladění DI grafu poskytuje Swinject rozšíření SwinjectPropertyLoader, které načítá konfiguraci z plist souboru, a SwinjectStoryboard — integraci se storyboardy přes speciální verzi UIStoryboard. Tyto nástroje jsou zvláště užitečné ve fázi převodu stávajícího projektu z ruční konstrukce objektů na DI: vývojář může postupně registrovat služby, kontrolovat graf závislostí pomocí testů a logování chyb řešení, aniž by zastavil vývoj hlavních funkcí aplikace.
Swinject také poskytuje integraci s RxSwift a Combine přes rozšíření SwinjectAutoregistration pro automatické řešení závislostí podle typů parametrů inicializátoru bez explicitní registrace továren. To snižuje objem registračního kódu pro jednoduché služby: stačí zavolat container.register(ServiceProtocol.self) bez uvedení továrny a Swinject samostatně postaví továrnu na základě reflexe Signal poskytované běhovým prostředím Swift. Tento přístup se doporučuje pro služby, jejichž konstruktor přijímá pouze základní typy a nevyžaduje složitou logiku při vytváření.
Často kladené otázky
Swinject je napsán v čistém Swiftu bez generování kódu a reflexe. Na rozdíl od Needle nevyžaduje generování zdrojového kódu a ve srovnání s Dipem poskytuje vestavěnou podporu Storyboard Injection, což zjednodušuje integraci do stávajících UIKit projektů.
Přidejte balíček na URL github.com/Swinject/Swinject přes Xcode v menu File — Add Packages. Instalace přes CocoaPods a Carthage je také dostupná. Po instalaci importujte modul Swinject a vytvořte instanci Container.
Ano, Swinject je plně kompatibilní se SwiftUI. Závislosti se vkládají přes inicializátory View nebo přes Environment, kde je kontejner předáván jako EnvironmentObject. Swinject není závislý na UIKit a funguje stejně s oběma frameworky.
Vytvořte samostatný kontejner pro testy a nahraďte reálné služby mocky. Swinject umožňuje přepisovat registrace bez změny kódu spotřebitelů. Každý test získá izolovaný kontejner s minimální sadou závislostí.
Pro analytiku použijte scope container, aby všechny obrazovky odesílaly události přes jednu instanci. To zaručuje jednotnou frontu odesílání a správnou dávkovou agregaci bez duplikace dat mezi různými spotřebiteli.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také