Swinjectは、iOSアプリケーションでDependency Injectionパターンを実装するSwift用のDIコンテナです。このフレームワークは依存関係の作成と注入を自動化し、手動によるオブジェクトとファクトリの管理を不要にします。GitHub上のSwinjectによると、ライブラリはConstructor Injection、Property Injection、Method Injectionをサポートし、ライフタイム管理のための柔軟なスコープシステムを提供します。
重要ポイント
Swinjectは、iOS、macOS、watchOS向けアプリケーションでの依存性注入を簡素化するために設計された、Swift言語用のオープンソースDIコンテナです。フレームワークはService Locatorアプローチを採用:サービスは中央コンテナに登録され、インスタンスが要求されるとコンテナが自動的に依存関係グラフを解決します。
Dependency Injection(DI)は、オブジェクトが内部で依存関係を作成するのではなく、外部から受け取るデザインパターンです。これによりコンポーネント間の結合度が低下し、単体テストが容易になり、消費者コードを変更せずに実装を置き換えられます。
Martin Fowler(2004)によると、DIはInversion of Controlの特定のケースであり、コンストラクタ、プロパティ、またはメソッドインジェクションを通じて実装されます。Swinjectはこのプロセスを自動化し、手動でファクトリやサービスロケータを記述する必要をなくします。
3つ以上のサービスが相互依存関係を持つプロジェクトでSwinjectを使用してください。手動によるオブジェクト構築は初期化コードの肥大化とテスト容易性の低下を招きます。
SwinjectはAppleエコシステムと緊密に統合され、Swift 3.0以降のすべてのバージョンをサポートします。フレームワークはブリッジを通じてObjective-Cと互換性があり、完全なコード移行なしで既存の混在言語プロジェクトに導入できます。これは特に5年以上の開発歴を持つ大規模アプリケーションで重要です。
SwinjectコンテナはContainerクラスによって実装され、登録されたサービスのレジストリを保存します。resolveメソッドが呼び出されると、コンテナはオブジェクトを作成し、登録グラフを通じてすべての依存関係を再帰的に解決します。
Containerは、抽象化とその実装の間のマッピングが登録される中心的なオブジェクトです。Serviceは契約を定義するプロトコルであり、Componentはそのプロトコルを実装するクラスです。登録はregisterメソッドを使用して行われ、サービスタイプとファクトリを受け取ります。
let container = Container()
container.register(Networking.self) { _ in
NetworkService()
}
let service = container.resolve(Networking.self)
resolveメソッドは、指定されたプロトコルに登録された具体的な実装のインスタンスを返します。依存関係が登録されていない場合、コンテナは開発中の迅速な問題発見のために致命的エラーをスローします。
各登録は、ファクトリ関数と選択されたスコープを持つエントリを作成します。1つのサービスに異なる名前で複数の登録を持たせることができ、名前によって特定の実装を選択できます — 異なる環境(開発、ステージング、本番)に便利です。
依存関係解決プロセスは再帰的に機能します:コンテナがComponentインスタンスを作成するとき、そのイニシャライザを分析し、各パラメータに対して対応する型でresolveを呼び出します。依存関係がさらに自身の依存関係を持つ場合、グラフ全体が完全に構築されるまでプロセスが続行されます。ネストの深さは利用可能なメモリによってのみ制限されますが、実際には5レベルを超えることはほとんどありません。
Swinjectは3つの主要な依存性注入方法をサポートしており、それぞれアーキテクチャのコンテキストに応じて適用されます。
Constructor Injectionは、イニシャライザのパラメータを通じて依存関係を注入します。これは推奨される方法で、オブジェクトが作成時から常に有効な状態であることを保証します。Swinjectはコンストラクタに渡されたすべての依存関係を自動的に解決します。
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は、初期化後にオブジェクトのプロパティを設定して依存関係を注入します。依存関係がオプションであるか、コンストラクタを通じて渡せない場合に使用されます。例えば、Storyboardを扱う場合、view controllerは自動的に作成されます。Swinjectは、明示的なresolve呼び出しなしで実行時にプロパティを自動注入する@Injectアノテーションをサポートしています。
Property Injectionを使用する場合、オブジェクトへの最初のアクセス前に依存関係が設定されていることを確認することが重要です。そうしないと、プロパティはnilのままとなり、予期しないクラッシュを引き起こします。SwinjectはImplicitly Unwrapped Optionalメカニズムと依存関係グラフ解決段階での厳格な検証を通じてこの問題を解決します。
Method Injectionは、メソッドパラメータを通じて依存関係を注入します。これは単一の操作を実行するためにのみ必要で、オブジェクトの永続的な状態として保存すべきでないサービスに使用されます。最も一般的ではありませんが、コールバックに便利な注入方法です。
ObjectScopeは、Swinjectコンテナ内で作成されたインスタンスのライフタイムを決定するメカニズムです。フレームワークは、ObjectScopeProtocolを通じてカスタムスコープを作成する機能とともに、3つの組み込みスコープを提供します。
graphスコープはデフォルト値です。resolve呼び出しのたびに新しいインスタンスが作成され、依存関係グラフ解決の期間のみ生存します。キャッシュによるメモリリークを排除するため、ステートレスサービスにとって安全な選択です。
containerスコープはコンテナ内のシングルトンです。インスタンスは最初のresolveで1回作成され、以降のすべてのリクエストで返されます。共有状態を持つサービス(データキャッシュ、ロガー、アプリケーション設定)に適しています。
transientスコープは、キャッシュなしでresolve呼び出しのたびに新しいインスタンスを作成します。再利用する必要のない軽量オブジェクトに使用されます — 例えば、特定のHTTPリクエストを処理するモジュール。
| スコープ | ライフタイム | 推奨用途 |
|---|---|---|
| graph | グラフ解決の期間 | デフォルトのステートレスサービス |
| container | コンテナの全ライフタイム | シングルトン:キャッシュ、ロガー、ネットワーククライアント |
| transient | キャッシュなし | 1回限りの軽量オブジェクト |
実際のiOSプロジェクトにSwinjectを統合するには、アプリケーション起動時にコンテナを初期化することから始まります — AppDelegateまたはシーンで。Assemblyを使用して登録を構造化することを推奨します:関連するサービスをグループ化する個別のクラスまたは構造体。
Swift Developer Communityの調査(2025)によると、43%のiOS開発者が商用プロジェクトでネットワーク層、リポジトリ、ナビゲーションコーディネータの依存関係管理にDIコンテナを使用しています。Swinjectは最小限の構文とObjective-C互換性により、最も人気のあるソリューションであり続けています。
Storyboard InjectionはSwinjectのユニークな機能です:コンテナはAppDelegateに追加コードを書かずに、Storyboardから作成されたview controllerに自動的に依存関係を注入します。これはinit(container:)メソッドを介してUIStoryboardに渡される特別なリゾルバを使用し、view controllerの作成をインターセプトして登録された依存関係を注入します。
大規模プロジェクトでは、Swinjectをナビゲーションコーディネータと組み合わせることができます:コーディネータはコンテナを受け取り、resolveを通じて依存関係を解決して画面を作成し、シーン全体の単一設定ポイントを維持します。
Assemblyアーキテクチャは登録を整理するための推奨パターンです。各Assemblyは関連サービス(NetworkingAssembly、DatabaseAssemblyなど)をグループ化し、他のAssemblyに依存できます。コンテナ初期化時に、すべてのAssemblyがロードされ、サービスを登録し、明確な責務分離を提供し、数十のサービスを持つ大規模プロジェクトでのDI設定のナビゲーションを簡素化します。
DIグラフのデバッグのために、Swinjectはplistファイルから設定をロードするSwinjectPropertyLoader拡張と、特別なバージョンのUIStoryboardを通じたストーリーボード統合であるSwinjectStoryboardを提供します。これらのツールは、既存プロジェクトを手動オブジェクト構築からDIに移行する際に特に有用です:開発者はメイン機能の開発を止めることなく、テストと解決エラーログを通じて依存関係グラフを確認しながら、徐々にサービスを登録できます。
Swinjectはまた、明示的なファクトリ登録なしでイニシャライザパラメータタイプに基づく自動依存関係解決のためのSwinjectAutoregistration拡張を通じて、RxSwiftおよびCombineとの統合を提供します。これにより単純なサービスの登録コード量が削減されます:ファクトリを指定せずにcontainer.register(ServiceProtocol.self)を呼び出すだけで、SwinjectはSwiftランタイムが提供するSignalリフレクションに基づいて自動的にファクトリを構築します。このアプローチは、コンストラクタが基本型のみを受け取り、複雑な作成ロジックを必要としないサービスに推奨されます。
よくある質問
Swinjectはコード生成やリフレクションなしの純粋なSwiftで書かれています。Needleとは異なりソース生成が不要で、Dipと比較して組み込みのStoryboard Injectionサポートを提供し、既存のUIKitプロジェクトへの統合を簡素化します。
XcodeのFile → Add PackagesメニューからURL github.com/Swinject/Swinjectでパッケージを追加します。CocoaPodsおよびCarthage経由のインストールも可能です。インストール後、Swinjectモジュールをインポートし、Containerインスタンスを作成します。
はい、SwinjectはSwiftUIと完全に互換性があります。依存関係はViewイニシャライザまたはEnvironmentを通じて注入され、コンテナはEnvironmentObjectとして渡されます。SwinjectはUIKitに依存せず、両方のフレームワークで同様に動作します。
テスト用に別のコンテナを作成し、実際のサービスをモックで置き換えます。Swinjectは消費者コードを変更せずに登録を上書きできます。各テストは最小限の依存関係セットを持つ独立したコンテナを取得します。
アナリティクスにはcontainerスコープを使用し、すべての画面が単一のインスタンスを通じてイベントを送信するようにします。これにより、異なる消費者間でのデータ重複なしに、統合された送信キューと正しいバッチ集約操作が保証されます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。