Swift

DI & Swinject

GREEN.1229 2021. 8. 3. 22:07

안녕하세요. 그린입니다🟢

이번 포스팅에서는 Swinject에 대해 알아보겠습니다🧑🏻‍💻

 

Swinject?

Swinject는 의존성 주입 프레임워크입니다.

한마디로 정의하기가 참 어려운데 그럼 먼저 의존성 주입이 어떤것인지 알아봐야겠죠?

 

의존성 주입?

Dependency Injection이라고도 불리며 객체지향을 설계하고 코딩할때 중요한 부분입니다.

복잡한 개발을 하면 할수록 코드간 의존성이 생길수가 있습니다.

예를들어 간단히 아래와 같은 코드가 있다고 가정해봅시다.

class Person {
    var action = Action()
    
    func startWalk() {
    	self.action.walk()
    }
}

이럴때 startWalk 함수 호출을 하기 위해서는 Action 클래스가 정의되야합니다.

이럴경우 Action과 Person사이 결합도가 증가하고 의존성이 생깁니다.

 

의존성이 생기면 안좋은점?

위와 같은 코드에서 Action의 내부구현이 바뀌면 Person의 startWalk 및 Action과 결합한 모든 부분들을 바꿔줘야합니다.

즉, 객체지향으로 이점을 가져가려하지만 코드의 재사용성이 떨어지게되죠.

이걸 어디서 많이 봤는데... 그.. SOLID의 마지막!!

Dependency Inversion Principle (의존 역전 원칙)에 위배된다고 볼 수 있습니다.

의존 역전 원칙은 의존 관계가 생길때 변하기 쉬운거 보다 변하기 어려운 것에 의존해야 한다는 원칙입니다.

즉 DIP를 위배하지 않으려면 의존 시 클래스보다는 인터페이스 혹은 추상 클래스와 관계를 맺는게 맞습니다.

 

자 그럼 의존성에 대해 간략하게? 알아보았으니 의존성 주입을 왜 해야하는가!?에 대해 보겠습니다.

 

의존성 주입을 해야하는 이유? 하면 좋은점!

- 테스트

- 코드 재사용성

- 유연성

이렇게 크게 3가지로 정리할 수 있습니다.

저는 특히 마지막 유연성에 초점을 두고 싶습니다.

위의 코드를 통해 의존성이 발생할때 문제점을 봤었는데 유연성을 가지지 못했습니다.

만약 올바른 의존성 주입을 통한다면 Action클래스를 고쳐도 해당 클래스를 참조한곳이 없을테고 많은 부분을 수정할 필요가 없겠죠!

이렇게 이후 기능이 많아지고 꼬이는 경우를 꼭 생각하며 의존성 주입을 신경쓰면 좋습니다!

 

자 그럼 의존성과 의존성 주입이란 무엇인지 그리고 왜 해야하는지에 대해 알아보았습니다.

(너무 간략해서 의존성 주입에 대해서는 좀 더 자세히 포스팅을 할 계획입니다.. 계획..!)

돌고돌아 멀리왔지만 이제 본격적으로 오늘의 학습 주제인 Swinject에 대해 알아보겠습니다😊

 

Swinject

Swinject는 Swift용 경량 종속성 주입 프레임워크입니다.
DI(Dependency Injection)는 종속성을 해결하기 위해 IoC(Inversion of Control)를 구현하는 소프트웨어 디자인 패턴입니다.
패턴에서 Swinject는 앱을 느슨하게 결합된 구성 요소로 분할하여 더 쉽게 개발, 테스트 및 유지 관리할 수 있도록 도와줍니다.
Swinject는 Swift 일반 유형 시스템과 앱의 종속성을 간단하고 유창하게 정의하는 일급 함수로 구동됩니다.

라고 Swinject 리드미에 나와있습니다.

위의 앞서 간략히 설명했던것과 같이 Swift용의 의존성 주입 프레임워크다~

또 의존성 주입을 할때의 장점들이 당연히 Swinject에서 도와준다~ 라고 정리해볼 수 있습니다.

 

그럼 대체 Swinject를 프로젝트에서 어떻게 쓸것인가?

구현은 어떻게 해줄 수 있을까?

이 부분은 리드미에 정리된걸 토대로 이해해보겠습니다.

 

제일먼저 의존성 주입은 Class 외부에서 해야합니다.

그렇다면 어디일까요? 앱의 설정을 관리해주는 AppDelegate 파일에서 의존성 주입을 시켜주면 됩니다.

import Swinject

 

그다음 의존성을 위한 서비스를 등록하고 가져와서 사용한다!

이 개념의 원칙을 잘 기억해보겠습니다.

let container = Container()
container.register(Animal.self) { _ in Dog(name: "MOMO") }
container.register(Person.self) { r in
    PetOwner(pet: r.resolve(Animal.self)!)
}

- 의존성을 주입해주는 큰 틀인 컨테이너를 생성합니다.

- 해당 컨테이너에 주입시켜줄 의존성의 서비스를 등록합니다.

let person = container.resolve(Person.self)!
person.play() // prints "I'm playing with MOMO."

- resolve를 이용해 사용할 서비스 인스턴스를 가져옵니다.

 

음.. 아무리 쉽게 이해하려해도 쉽지가 않은 대목이네요🐼

한가지는 확실히 짚고 넘어가면 register로 등록 resolve로 사용!

 

실제로 앱딜리게이트에서 등록하고 사용한다면 이렇게 해볼 수 있을것입니다.

let container = Container()
container.register(FirstViewModel.self) { r in FirstViewModel() }
container.register(SecondViewModel.self) { r in SecondViewModel() }

container.register(FirstViewController.self) { r in
    let controller = FirstViewController()
    controller.viewModel = r.resolve(FirstViewModel.self)
    
    return controller
}
container.register(SecondViewController.self) { r in
    let controller = SecondViewController()
    controller.viewModel = r.resolve(SecondViewModel.self)
    
    return controller
}

self.window?.rootViewController = container.resolve(FirstViewController.self)

앱딜리게이트에서 하나의 컨테이너를 만들고 여러 의존성을 주입시키고 사용함으로 앱 전체의 의존성을 편리하게 관리할 수 있습니다.

 

이번 포스팅에서는 Swinject에 대해 간략히 훑어보고 어떻게 사용하고 흐름이 어떤것인지 알아보았습니다.

Swinject를 더 잘 사용하려면 Swinject의 다양한 요소들을 알아야하는데 아직은 학습중이라..!

보완은 또 성장한다음 해보도록 하겠습니다😆

 

[참고자료]

https://github.com/Swinject/Swinject

 

GitHub - Swinject/Swinject: Dependency injection framework for Swift with iOS/macOS/Linux

Dependency injection framework for Swift with iOS/macOS/Linux - GitHub - Swinject/Swinject: Dependency injection framework for Swift with iOS/macOS/Linux

github.com

https://medium.com/flawless-app-stories/ios-dependency-injection-using-swinject-9c4ceff99e41

 

iOS Dependency Injection Using Swinject

In this article, you’ll find everything you should know about iOS Dependency Injection with Swinject.

medium.com