Clean Architecture에서도 자주 언급되는 용어이고, Software Engineering 에서도 자주 언급되는 단어 입니다. 직역을 하자면 의존성 주입이라고 하는데 사실 직역을 했을때 용어를 보고 어떤 의미인지 이해 하기에는 조금 힘든면이 있습니다.
해당 포스팅은 DI에 대한 내용이 아니기 때문에 간략하게 설명하자면 객체간의 의존관계를 줄여서 수정에 대한 유연성을 높이고, 확장성을 향상시킬수 있는 장점이 있습니다. 여기에 또하나의 장점으로는 unit test를 용이하게 해주는 역할도 있습니다.
조금 더 어렵게 말하면, 사용하려고 하는 하나의 객체(1)를 초기화 할 때에 해당 객체 내에서 사용하는 다른 객체(2,3,4...)들을 객체 내에서 생성하지 않고 외부에서 객체(2,3,4...)를 생성해서 사용하려고 하는 객채(1)에게 넘겨 줌으로서 사용 되는 객체(2,3,4,...)의 코드가 추후에 변경이 되더라도 기존 객체(1)는 다시 빌드 하지 않고도 사용할 수 있다 라고 설명할 수 있네요...뭐..그냥 이렇다고 하는 겁니다...
사실 Android에는 google에서 공식적으로 추천을 하는 DI module이 있습니다. 다들 들어보셨을것 같은 dagger2나 Hilt가 그것들이죠.
오늘 살펴볼 Swinject는 Swift에서 사용되는 DI module인데 사실 dagger2에 비하면 아주 사용법도 쉽고 기능도 없습니다(?!).
Swift에서는 사실 custom 으로 DI를 simple하게 만든다고 해도 시간이 많이 들어가지 않고 개발자 마다 혹은 개발 단체 마다 필요한 내용만 구현해서 사용할 수 있기 때문에 Swinject와 같은 module이 많이 사용 되지 않는것 같습니다. 필자도 사실 DI를 관리하는 class/module을 simple하게 만들어서 사용을 하다가 갑작스러운 변덕으로 swinject를 사용하게 되었습니다.
github 상에 기본적인 사용예제가 있고, 이를 거의 그대로 번역해서 올려둔 블로그도 쉽게 찾을 수 있기 때문에 여기서는 저의 주관(?)적인 사용법만 간단하게 살펴 보고, Scope에 대해서 정리하겠습니다.
기본적인 사용법은 아래 Ref의 github의 readmi를 보시면 예제와함께 잘 나와 있어서 여기서는 크게 언급 하지는 않고 간략하게 제가만든 예시를 첨부해서 간략하게 보겠습니다.
final class DIContainer {
static let shared = DIContainer()
var container: Container = Container()
private init(){}
func initContainer() -> () {
self.container.register(AuthService.self){ _ in
AmplifyAuthService()
}
self.container.register(TestViewServiceProvider.self){ resolver in
TestViewServiceProviderImpl(authService: resolver.resolve(AuthService.self)!)
}
self.container.register(TestViewReactor.self){ resolver in
TestViewReactor(serviceProvider: resolver.resolve(TestViewServiceProvider.self)!)
}
}
}
네. 맞습니다. DI를 관리하는 class이고 static shared를 이용해서 공용으로 사용하실 수 있고, 초기화는 AppDelegate 혹은 SceneDelegate에서 앱 launch 직후 초기화를 하면 이후 자유롭게 사용할 수 있습니다.
기본적으로 Container라는 instance를 관리,저장하는 instance를 만들어서 DI를 관리할 수 있습니다.
초기화 하는 시점에 register method를 이용해서 이후 사용하려고 하는 class instance를 등록해 둘 수 있고,
간단하게 register를 이용해서 사용하려고 하는 instance를 등록 resove를 이용해서 등록되어 있는 instance를 신규 생성/할당 혹은 기존 생성되어 있는 instance를 재사용 할 수 있습니다.
위의 초기화 과정을 거치고 난 후 타 class내에서 등록된 instance를 사용할 때에는 아래와 같은 방법으로 사용할 수 있습니다.
//
var testServiceProvider: TestViewServiceProvider? = DIContainer.shared.container.resolve(TestViewServiceProvider.self)