DI 컨테이너

준우·2024년 2월 5일
0

Swift 이야기

목록 보기
10/19
post-thumbnail

DI 컨테이너란?

  • 의존성 주입(=DI) 를 할 때 객체를 생성해서 주입하는 것을 도와주는 것

DI 컨테이너 생성 예제

  • 프로토콜 예제
protocol AwesomeDICProtocol {
    func register<T>(type: T.Type, dependency: Any) // 의존성 등록
    func resolve<T>(type: T.Type) -> T? // 의존성 해결
}
  • 컨테이너 생성 예제 코드
final class DIContainer: AwesomeDICProtocol {
    static let shared = DIContainer()

    // 의존성을 등록할 딕셔너리를 선언합니다.
    private var dependencies: [String: Any] = [:]

    // 의존성을 등록하는 메서드
    func register<T>(type: T.Type, dependency: Any) {
        let key = String(describing: type)
        dependencies[key] = dependency
    }

    // 의존성을 해결하는 메서드
    func resolve<T>(type: T.Type) -> T? {
        let key = String(describing: type)
        return dependencies[key] as? T
    }

    private init() {} // 외부에서 추가 생성 방지
}
  • 사용 예시 코드
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let container = DIContainer.shared
    container.register(type: ToDoCRUDProtocol.self, dependency: ToDoManager()) 
  	// TodoManager 의존성 등록
		// TodoManager 의존성 주입도 여기서 하면 됩니다. 전 이번에 SB 를 사용했기때문에 viewDidLoad 에 했습니다.
     return true
}

// 뷰컨트롤러 : 스토리보드를 사용해서 여기에!! 
override func viewDidLoad() {
        super.viewDidLoad()
        viewModel = ToDoViewModel(todoService: DIContainer.shared.resolve(type: ToDoCRUDProtocol.self)!) // SB이라서 여기에 의존성 주입... ViewModel에 Service 주입
        setup()
    }

서비스 프로토콜 생성

  • 생성 예제 코드
protocol ToDoCRUDProtocol {
    var items: [ToDo] { get set }
    func addItem(item: ToDo)
    func deleteItem(at index: Int)
}

서비스 프로토콜을 채택한 매니저 혹은 서비스 객체 생성

  • 생성 예제 코드
// ToDo CRUDServiceable 구현
final class ToDoManager: ToDoCRUDProtocol {
    var items: [ToDo] = []

    func addItem(item: ToDo) {
        items.append(item)
    }

    func deleteItem(at index: Int) {
        if index < items.count {
            items.remove(at: index)
        }
    }
}

ViewModel 에서 의존성을 주입 받은 서비스를 사용하는 예시

  • 생성 예제 코드
import Foundation

class ToDoViewModel {
    let todoService: ToDoCRUDProtocol // 주입 받을 서비스

  	// 초기화
    init(todoService: ToDoCRUDProtocol) {
        self.todoService = todoService
    }

    var todos: [ToDo] {
        return todoService.items
    }

    var todosCount: Int {
        return todoService.items.count
    }

    func addNewToDo(item: ToDo) {
        todoService.addItem(item: item)
    }

    func deleteToDo(at index: Int) {
        todoService.deleteItem(at: index)
    }
}

결론

의존성 주입 컨테이너를 사용하여 의존성 주입을 하는 순서는 다음과 같다.

  • 의존성 주입 컨테이너를 생성한다. -> Ex) AwesomeDIProtocol 등
  • 내가 만들려는 객체를 추상화한 프로토콜을 정의한다. ToDoService 라면, ToDoProtocol 이라는 방식으로 만들면 됩니다.
  • 추상화한 프로토콜을 채택한 객체를 만듭니다. -> Ex) ToDoManager
  • ViewModel 에서 주입받을 프로토콜 타입을 선언한 후, init 생성자를 만듭니다. 그리고 ViewModel 내부 메서드는 프로토콜 타입을 채택하여 사용합니다.
  • AppDelegate 에서 사용하고자 하는 VC 또는 ViewModel 에 DI 컨테이너를 사용하여 의존성 주입을 해주면 끝이 납니다.

0개의 댓글