MVC 패턴을 적용하여 개발하다 보면 Model, View, Controller 셋 중에 어디에 넣어야 할 지 애매한(?) 상황이 꽤 자주 발생했는데요!

사실 MVC 패턴도 완벽하게 이해하고 적용하고 있지 않기 때문에라는 생각이 들었지만 MVVM 패턴의 흐름도를 보고 꽤 흥미가 당겨 공부해보기로 했지만

막상 적용해보려 하니 꽤나 복잡한 흐름이더군요… 🥲

그래서 iOS-Clean-Architecture 예제를 하나하나 뜯어가며 MVVM에 대해서 파악해보고자 합니다!

예제에 있는 계층도도 프로젝트에 맞게 이해하기 쉽게 되어있지만 막상 코드를 파해쳐 보면 어느새 숲 한가운데서 길을 잃고 있는 저를 발견하곤 했는데 천천히… 정말 아주 천천히.. 파해쳐 보겠습니다.

Layer

위 이미지에는 Presentation, Domain, Data 크게 세가지 영역으로 표시했지만 부가적으로 앱의 셋팅과 흐름을 담당하는 Application, 네트워크와 관련된 객체들을 가지는 Infrastructure 가 존재합니다.

Application Layer

본격적으로 해부를 시작할 계층은 Application인데요!

앱 실행전 객체들의 의존성을 주입하고 셋팅 하는 계층입니다. 이 예제에서는 AppDelegate에서 했지만 저는 SceneDelegate로 옮겨서 적용했다. AppDelegate와 SceneDelegate의 차이점도 나중에 따로 정리를 한번 해야겠어요!

자… 어디보자.. AppDelegate는 알겠는데.. 나머지는 너무 생소하네요.. 우선 AppDlegate 부터 봅시다!

AppDelegate

SceneDelegate라 생각하고 보렵니다!

이 델레게이트는 AppDIContainerAppFlowCoordinator를 가지고 있네요. rootViewController가 될 UINavigationController를 선언해 준뒤 코디네이터에 네비게이션컨트롤러와 addDIContainer를 인자로 넘겨 객체를 생성해주네요!

그러고 .start로 앱을 실행하려나봐요

음 그러니까 AppDelegate에서는 앱의 의존성(App Dependencies)을 정의하고 흐름을 담당하는 코디네이터에게 네비게이션컨트롤러와 AppDIContainer를 넘겨 다음 작업을 하게끔 넘겨주는 역할! 까지 하는것 같습니다

그러면 AppDIContainer는 과연 어떤 Dependencies를 정의하고 있는지 봅시다!

AppDIContainer

이녀석이 AppDIContainer 이군요..!

어디보자..

AppConfiguration이 존재하네요 이 녀석은 api의 key, baseURL과 같은 앱과 관련되어 정의되는 값들을 info.plist에 저장해 놓고 불러오는데 아직 저는 api를 사용하긴 하지만..? 이정도 까지 아니기에 패스..

Configuration을 정해준다음 네트워크도 config해주네요 저는 이러한 config에 대한 정보를 APIEndPoint 객체에 담아주기로 했기 때문에 넘어갑시다!

그다음

func makeMoviesSceneDIContainer() -> MoviesSceneDIContainer { }

이 함수를 호출하여 MoviesSceneDIContainer 를 생성 및 반환 하네요.

AppDIContainer 의 역할은 앱의 관련된 기본적인 key, baseURL(s)를 불러오고 configure을 정의 해줌 -> network와 연동이 필요한 service들을 생성해줌 -> networkService들을 인자로 넘겨 SceneDIContainer를 생성 및 반환 하는 역할!

의 순서로 역할을 정의 해볼 수 있을 것 같습니다!

MoviesSceneDIContainer

자자자 코드를 파해치다 보면 길을 잃기 너무 쉽기 때문에 저희가 지금 왜 여기 바로 MoviesSceneDIContainer에 와있는지 정리해봅시다!

AppDelegate에서 AppFlowCoordinator을 통해 앱을 움직이려 하는데 의존성 주입이 필요하게되죠!

그래서 AppDIContainer에서 앱관련 configure와 NetworkService 객체 생성 한 뒤 본격 적인 이 서비스들과 함께 Presentation, Domain, Data의 의존성 주입을 MoviesSceneDIContainer에서 하도록 부탁합니다!

그래서 이 녀석에서 많은 객체들이 유기적인 흐름으로 이루어 질 예정인거 같군요!

자 그럼 이제 한번 봐 봅시다.

예제 코드로 봐보려 했으나…! 너무 많은 Scene에 대한 의존성 주입이 얽혀있어 설명하기엔 너무 장황해질거 같아 단일 Scene에 대해서 저의 예제코드(?)로 살펴 보려 합니당.

BanchanSceneFlowCoordinatorDependencies는 뭐하는 프로토콜이야? 는 나중에 다루도록 하구요.

외부에서 주입받은 networkService를 Repository에 주입해서 Repository 객체 생성

RepositoryUseCase 에 주입하여 객체 생성

UseCase 들을 ViewModel 에 주입하여 객체생성

아 이때 Repository나 UseCase들을 필요한 만큼 생성해서 넣어 줄 수 있어요 저는 다 단일 단계라 하나씩 넣었습니다.

마지막으로 ViewModel 을 가지고 있는 ViewController 를 생성하는 단계 까지가 의존성 주입이라 볼 수 있습니다!

흠.. 🧐 왜 이런짓을 하냐고요? 나중에 TDDSOLID 에 대해 다룰 수 있음 좋겠지만 우선 해야합니다.. 우선

그런데 Flow Coordinator와 위에서 말한 프로토콜에 대해 말을 안했죠?

이제 진짜 본격적으로 App이 아니라 Scene의 Flow를 정하러 가봅시다!

가기 전 다시한번 MoviesSceneDIContainer는 Presentaion, Data, Domain과 Network의 의존성 설정의 역할을 한다! 라고 정리해볼 수 있겠습니다.

MoviesSearchFlowCoordinator

와.. 아찔하네요.. 음 우리는 시작이 중요한거니까.. 시작에 관련된 것만 짤라서 봐봅시다!

음 우선 navigationController를 가지고 있고 음? 아까 봤던 MoviesSearchFlowCoordinatorDependencies가 여기 프로퍼티로 존재하네요?

저건 뭐하는거지

SceneFlowCoordinator가 MoviesSearchFlowCoordinatorDependencies 를 프로퍼티로 가지고 있고 저 프로토콜은 MoviesSearchDIContainer가 채택하고 있는것을 위에서 확인 할 수 있습니다.

프토토콜 내부 함수들을 살펴보면 앱 흐름 전체에 필요한 ViewController를 만들어주는 함수들을 가지고 있는데요!

MoviesSearchDIContainer 에서 UseCases, Repositories, ViewModels, Storages들은 내부에서 자체적으로 생성 및 의존성 주입을 시켜 준 뒤 결과물로 ViewModel을 가지고 있는 ViewController를 외부로 반환시켜 주는 흐름으로 이루어 져있네요!

MoviesSearchFlowCoordinator 는DIContainer에서 ViewController를 받아 앱의 흐름을 제어해주는 역할! 이라고 정리해 볼 수 있을것 같아요

그래서 저 start() 메소드가 호출될시 NavigationViewController에 첫 ViewController가 push 되게 되어 첫화면이 load 되는 것이죠!

후아 길었네요 이제 App을 준비하기 위한 단계인 Application을 다 살펴 본거 같아요.

그럼 저 start()메소드는 어떤식으로 AppDelegate에서 호출이 되는지 다시 한번 AppDelegate로 가볼까요?

ㅉㅏㄴ

기억 나시나요? AppDelegate에서 시작해서 AppDIContainer를 타고 들어가서 여기까지 온거에요!

한가지 빼먹은게 보이죠? 바로 AppFlowCoordinator 인데요 func application 내부를 보면 AppFlowCoordinator 객체를 생성 할때 앞서 셋팅 된 AppDIContainer를 주입시켜 주는데요 그렇게 생성된 appFlowCoordinator.start() 로 앱을 본격적으로 실행을 시켜준다! 라고 볼 수 있겠습니다.

그러면 AppFlowCoordinator를 한번 살펴 보면 되겠죠?

와 생각보다 간단하네요 복잡할줄 알고 긴장 좀 했는데 ㅎ..

이 코디네이터는 마지막 계층으로서 하위 DIContainer를 생성하고 그 DIContainer에서 SeceneFlowCoordinator를 생성해주고 그 Coordinator를 start 시켜줌으로써 RootViewController에 push 되는 것이군요!

이렇게 해서 App이 실행될때 각 계층의 모델들을 생성해주고 의존성 주입을 해준 뒤 ViewController간 이동을 다뤄주는 FlowCoordinator가 주가 되어 앱의 흐름을 계속 담당해주게 됩니다!

어때요 조금 이해가 가시나요?? 이게 그림이나 흐름도로 흐름을 그려주면 좋겠다 라는 생각이 들긴 하는데…. 잘 그려야 하는데 이게 또 괜히 이상하게 그리면 혼란스럽기만 할거 같기도 하고 저도 정리하면서 한번 도전해봐야겠어요!

우선 Application 끝! 사실 이것만 이해해도 뭐 다 이루었다 라고 말할 수 있을 것 같은데 ㅎ 다음은 Presentaion에서 본격적인 MVVM 패턴으로 어떻게 이루어 져있는지 확인해보겠습니다! 🙋‍♂️