Bibi's DevLog ๐ค๐
[iOS] DIContainer : ์์กด์ฑ ์ฃผ์ ์ ์ํ ๊ฐ์ฒด ๊ด๋ฆฌํ๊ธฐ ๋ณธ๋ฌธ
[iOS] DIContainer : ์์กด์ฑ ์ฃผ์ ์ ์ํ ๊ฐ์ฒด ๊ด๋ฆฌํ๊ธฐ
๋น๋น bibi 2022. 12. 5. 15:28์ฐธ๊ณ ๋ฌธ์ :
[DI] DI Container, IOC Container ๊ฐ๋ ๊ณผ ์์
DIContainer๋?
- DI = Dependency Injection ์์กด์ฑ ์ฃผ์
- ๋ฐ์์ ์ธ์คํด์ค๋ฅผ ๋ง๋ค์ด ์ฃผ์ ํด์ฃผ๋ ๊ฒ
- Container : ๋ชจ๋ ์ธ์คํด์ค๋ฅผ ๊ฐ์ง๊ณ ๊ด๋ฆฌํ๋ ๊ฐ์ฒด.
- register : ๋ด๊ฐ ์ฌ์ฉํ ์ธ์คํด์ค๋ฅผ ๋ง๋ค์ด ๋ฑ๋ก
- resolve : ํ์ํ ์ธ์คํด์ค๋ฅผ ๋ฌ๋ผ๊ณ ์์ฒญ
์ฆ DIContainer๋ ์์กด์ฑ ์ฃผ์ ์ ํ์ํ ๊ฐ์ฒด๋ค์ ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๋ ์ญํ ์ ํ๋ค.
- ์ ํ์ํ๊ฐ?
- ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ์ค๋ณต์ฝ๋๊ฐ ๋ง์์ง ๋
- ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ํ์ํ ํ๋ผ๋ฏธํฐ๊ฐ ๋ง์ ๋
์ฌ์ฉ๋ฐฐ๊ฒฝ
ํ๋ก์ ํธ๋ฅผ ํ๋ฉฐ ์ด๋ค ๊ฐ์ฒด๊ฐ ํ์ํ ๋, ์์ฑ์๋ก ์ฑ์ ์ฌ๊ธฐ์ ๊ธฐ์์ ๋ฌด๋ถ๋ณํ๊ฒ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์์๋ค.
๋, ์ด๋ฏธ ์์ฑํ๋ ์์ ๊ณผ ์์น๋ฅผ ๋ชจ๋ฅด๊ณ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ์ฌ๋ฌ ๋ฒ ์์ฑํ๋๋ฐ ์ด๋ ์์์ ๋ญ๋นํ๋ ํ์๋ผ๊ณ ์๊ฐํ๋ค.
๊ทธ๋์ ๋๋ ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ๋ฐฉ์์ ํต์ผํ๊ณ , ํ ๋ฒ ๋ง๋ ๊ฐ์ฒด๋ฅผ ์ฌ์ฌ์ฉํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค๊ณ ์ถ์ด์ DIContainer๋ฅผ ์ ์ฉํด ๋ณด์๋ค.
์ ์ฉ๋ฐฉ๋ฒ
DIContainer์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๊ฐ๋จํ๋ค.
์์ฑ๋ ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๋ ์ญํ ์ ํ๋ค.
import UIKit
class Container {
let environment: ContainerEnvironment
private var registeredObjects: [String: Any] = [:]
init(environment: ContainerEnvironment) {
self.environment = environment
}
// model, viewcontroller, coordinator๋ฅผ ์์ฑ ์์ ์ ๋ฑ๋กํจ
func register<T>(_ object: T) {
let key = String(describing: T.self)
registeredObjects[key] = object
}
// let value: Type = container.resolve() ๋ก ์ฌ์ฉ
func resolve<T>() -> T? {
let key = String(describing: T.self)
guard let object = registeredObjects[key],
let object = object as? T else {
print("โ ๏ธ\(key)๋ register๋์ง ์์")
return nil
}
return object
}
}
private var registeredObjects: [String: Any]
- ์ปจํ ์ด๋์ ๋ฑ๋ก๋ ๊ฐ์ฒด๋ค์ ์ ์ฅํ๋ ๋์ ๋๋ฆฌ.
- ํค : ๊ฐ์ฒด ์ด๋ฆ, ๊ฐ : ๊ฐ์ฒด
func register<T>(object:)
- ์ปจํ ์ด๋์ ๊ฐ์ฒด๋ฅผ ๋ฑ๋กํ ๋ ์ฌ์ฉํ๋ ๋ฉ์๋
func resolve<T>() -> T?
- ์ปจํ ์ด๋์ ๋ฑ๋ก๋ ๊ฐ์ฒด๋ฅผ ๊บผ๋ด ์ฐ๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ ๋ฉ์๋
let value: Type = container.resolve()
์ ๊ฐ์ด ํ์ ์ ๋ช ์ํ๊ณ ์ฌ์ฉํ๋ฉด ๋๋ค.- ์์ฒญํ ๊ฐ์ฒด๊ฐ ๋ฑ๋ก๋ ๊ฐ์ฒด๋ผ๋ฉด ๊บผ๋ด์ฃผ๊ณ , ๋ฑ๋ก๋์ง ์์ ๊ฐ์ฒด๋ผ๋ฉด nil์ ๋ฐํ
์ฌ์ฉ๋ฐฉ๋ฒ
- ์ฑ ๋ด์์ ์ด๋ค ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋, ์์ฑํ ๊ฐ์ฒด๋ฅผ Container์ ๋ฑ๋กํ๋ค.
let environment = LoginModelEnvironment { [weak self] completion in self?.container.environment.oAuthService.requestCode(completion: { result in completion(result) }) } let model = LoginModel(environment: environment) // ์์ฑ let viewController = LoginViewController(model: model) container.register(model) // ๋ฑ๋ก container.register(viewController)
- ์ดํ ๊ทธ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํด์ผ ํ ๋ ์๋ก ์์ฑํ์ง ์๊ณ , ์ปจํ ์ด๋์ ๋ฑ๋กํ๋ ๊ฐ์ฒด๋ฅผ ๊บผ๋ด์ฐ๋ฉด ๋๋ค.
guard let issueCoordinator: IssueCoordinator = container.resolve() else { return } issueCoordinator.fetchIssues()
์์ฉ - DIContainer๋ก ์ฝ๋๋ค์ดํฐ&๋ทฐ์ปจํธ๋กค๋ฌ ์ ๊ด๋ฆฌํ๊ธฐ
์์ธํ ๋ด์ฉ์ ์ฌ๊ธฐ ๋ฅผ ์ฐธ์กฐํด ์ฃผ์ธ์.
์ปจํ ์ด๋๋ ์ฑ ๋ด์ ๊ฐ์ฒด๋ค์ ๊ด๋ฆฌํด ์ฃผ๋ ์ญํ ์ ํ๋ค.
๊ทธ๋์ ์ดํ ์ฝ๋๋ค์ดํฐ ํจํด์ ์ ์ฉํ๋ค๊ฐ, ์ฝ๋๋ค์ดํฐ์ ๋ทฐ ์ปจํธ๋กค๋ฌ ์์ ํจ๊ป ๊ด๋ฆฌํด์ผ ํ ํ์๊ฐ ์๊ฒผ์ ๋ ์ด ์์ ์ ์ปจํ ์ด๋๊ฐ ํ๋๋ก ํ๋ค.
- ํค๊ฐ ๋ทฐ ์ปจํธ๋กค๋ฌ์ด๊ณ , ๊ฐ์ด ์ฝ๋๋ค์ดํฐ์ธ
registeredViewControllerCoordinator
๋ฅผ ๋ง๋ ๋ค. - ์ปจํ
์ด๋์
register(object:)
์์ ์์, ๋ฑ๋กํ๋ ๊ฐ์ฒด๊ฐUIViewController
์ผ ๋ ์์ด ๋๋ ์ฝ๋๋ค์ดํฐ๋ฅผ ์ฐพ์registeredViewControllerCoordinator
์ ๋ฑ๋กํ๋ค. func resolvePair(of viewController: UIViewController) -> Coordinator?
: ๋ทฐ ์ปจํธ๋กค๋ฌ๊ฐ ์ฃผ์ด์ก์ ๋, ๊ทธ ์ง์ด ๋๋ ์ฝ๋๋ค์ดํฐ๋ฅผ ๋ฐํํด ์ค๋ค.
class Container {
let environment: ContainerEnvironment
private var registeredObjects: [String: Any] = [:]
private var registeredViewControllerCoordinator: [UIViewController : Coordinator] = [:]
init(environment: ContainerEnvironment) {
self.environment = environment
}
// model, viewcontroller, coordinator๋ฅผ ์์ฑ ์์ ์ ๋ฑ๋กํจ
func register<T>(_ object: T) {
let key = String(describing: T.self)
registeredObjects[key] = object
if let viewControllerObject = object as? UIViewController {
registerPairCoordinator(with: viewControllerObject)
}
}
// let value: Type = container.resolve() ๋ก ์ฌ์ฉ
func resolve<T>() -> T? {
let key = String(describing: T.self)
guard let object = registeredObjects[key],
let object = object as? T else {
print("โ ๏ธ\(key)๋ register๋์ง ์์")
return nil
}
return object
}
private func registerPairCoordinator(with viewController: UIViewController) {
let viewControllerName = String(describing: type(of: viewController))
let allViewController = ViewControllerCoordinator.allCases
for oneCase in allViewController {
let oneCaseName = String(describing: oneCase) // Enum case์ ์ด๋ฆ์ String์ผ๋ก ๋ณํ
if oneCaseName == viewControllerName {
let coordinatorName = oneCase.rawValue
guard let coordinator = registeredObjects[coordinatorName],
let castedCoordinator = coordinator as? Coordinator else {
return
}
registeredViewControllerCoordinator[viewController] = castedCoordinator
}
}
}
func resolvePair(of viewController: UIViewController) -> Coordinator? {
return registeredViewControllerCoordinator[viewController]
}
}
๊ฐ์ ์
DIContainer๋ ์๋ฆฌ๊ฐ ๋ณต์กํ์ง ์์์ ์ ์ฉ์ด ์ฌ์ฐ๋ฉด์๋, ๊ทธ ํจ๊ณผ๋ฅผ ๋ฐ๋ก ์ฒด๊ฐํ ์ ์์ด์ ์ข์๋ค!
์ปจํ ์ด๋๋ฅผ ๋ง๋ค๊ณ ๋ฆฌํฉํ ๋ง์ ํ๋ ๊ฐ์ฒด ์์ฑ ์ฝ๋๊ฐ ์ฌ๊ธฐ์ ๊ธฐ์ ๋จ๋ฐ๋์ง ์๊ณ ,
์ฌ์ฉํ ๋๋ ํ ๋ฒ ๋ง๋ ๊ฐ์ฒด๋ฅผ ์ฌ๋ฌ ๋ฒ ์ฌ์ฌ์ฉํ ์ ์๊ฒ ๋์ด์ ์ข์๋ค.