Swifにおける依存性の注入(DI)について Swinjectを使って紐解く
この記事では、Swiftにおける依存性の注入についてをまとめていきます。
Dependency Injection
Dependency Injectionを直訳されたのが依存性の注入
です。
正直、依存性の注入と言われてもさっぱり意味がわかりません。
そこで、調べて見ることにしました。
Dependencyは、依存性と訳されることが多いですが、Objectと考える方がわかりやすい
とあります。
確かに、objectを注入すると考えると分かりやすいかもしれません。
必要なobjectを毎回初期化して利用するのではなく、
1つの場所でObjectを初期化しておき必要な時はそこからObjectを受け取るというイメージです。
今回利用するフレームワークのSwinject以外にもsharedを使って行うことがあります。
DIを行うことで、テストが簡単に書くことが出来るなどのメリットがあります。
では、実際のコードを見ながらDIについて考えたいと思います。 ここでは、 DIを行うフレームワークのSwinjectを使ってみました。
//ViewControllerAssembly import UIKit import Swinject final class ViewControllerAssembly: Assembly { func assemble(container: Container) { //MARK: -ReaderViewController container.register(ReaderViewController.self) { resolver in let viewController = UIStoryboard.instantiateViewController(of: ReaderViewController.self) viewController.viewModel = resolver.resolve(ReaderViewModel.self)! return viewController } } }
containerは、複数個のオブジェクトを管理するものです。DIで実装していくと引数が多くなるため同じオブジェクトをまた生成するというコストを削減させることができる。
そのcontainerに、container.registerでViewControllerに登録して行きます。
instantiateViewController
はstoryboardからViewControllerを作成する方法です。Swinjectでは、Swinjectstoryboardというものもあるのでそちらを利用するのもおすすめです。
そして、下記のコードでViewModelをcontainerに登録し、それをresolver.resolve
で呼んでいます。
最後にreturnで値を返しています。
//ViewModelAssembly import Swinject final class ViewModelAssembly: Assembly { func assemble(container: Container) { //MARK: - ReaderViewModel container.register(ReaderViewModel.self) { (resolver) in return ReaderViewModel() } } }
//Container+Extension import Swinject extension Container { static let shared = assembler.resolver private static let assembler = Assembler([ ViewControllerAssembly(), ViewModelAssembly(), ]) }
Container+Extensionでは、 ViewControllerAssembly( )
,ViewModelAssembly( )
の二つをShredで呼べるようにしています。これを行うことで2つのassemblyをシングルトンとして利用することができます。
//UIViewController.Container+Extension import Swinject import UIKit extension ReaderViewController { static func make() -> ReaderViewController { return Container.shared.resolve(ReaderViewController.self)! } }
このmake( )
を使うことで、Swinjectを使ってオブジェクトを外部から注入することができます。
実際にAppDelegateでwindow?.rootViewController = ReaderViewController.make()
でクラスの初期化を行なっています。