Overview
UIKit 애플리케이션의 기본 개발 패턴은 Cocoa MVC였다. 대표적으로 View Controller와 같이 책임이 결합된 경우를 생각해 볼 수 있다. 이때, 개발자가 코드를 잘 못 디자인하면 한 객체의 책임이 커져버리는 문제가 생긴다. 코드를 리팩터링 하기 위해 역할과 책임을 다시 나눠본다.
Problem
objc.io 사이트의 Ash Furrow 님이 작성하신 Introduction to MVVM 자료를 인용하였다.
Cocoa MVC에서 활용되는 결합된 역할의 대표 사례인 View controller는 UIKit 어플리케이션에서 주요하게 사용되는 클래스이다. Cocoa MVC를 UIKit 애플리케이션의 실제 클래스 다이어그램 구조로 표현하면 다음과 같다.
ViewController는 View 계층을 관리하면서도 Model과 View의 데이터 흐름을 중재하는 Controller 역할을 함께 수행하기 때문에 앱 개발 과정에서 많은 논리들이 ViewController에 배치될 가능성이 높다. 작은 규모의 개발 프로젝트에서는 개발 시간을 단축하기 좋은 방법일 수 있으나 규모가 커질수록 코드를 관리하기 어려울 수 있다.
Solutions
Core Idea
ViewController에 구현된 주요 논리를 추상화할 수 있다. 예를 들어 MVC에서 ViewController는 중재자 Controller의 역할을 하기 때문에 ViewController에는 필연적으로 Model 객체를 관리하는 코드를 갖고 있다. Model의 Controller 객체를 통해 Model을 관리하고 ViewController가 Model Controller에 관리 책임을 위임하는 전략을 통해 ViewController가 데이터를 보여주는 역할에 집중할 수 있도록 개선해 볼 수 있다.
MVVM
MVVM은 MVC와 마찬가지로 View와 Model을 분리해주기 때문에 비슷해 보인다. 다만 어떤 구성요소가 있는지 그리고 어떻게 구성요소 서로가 상호작용하는지 메커니즘에서 미묘한 차이를 보인다.
Responsibility
Model
Model은 MVC에서의 Model처럼 어플리케이션의 데이터나 로직을 캡슐화한 역할을 의미한다. 재사용성을 위해 UI와 완전히 독립적인 관계를 갖는다.
View
ViewController는 더이상 Model과 View의 중재자 Controller역할을 하지 않는다. MVVM에서는 사용자 액션 등의 이벤트를 받고 사용자에게 시각적으로 어떻게 보이는지를 관리하는 View의 역할을 담당한다.
ViewModel
ViewModel은 View와 Model의 중재자 역할을 담당한다. 따라서 ViewModel에는 View와 Model 간의 상호작용에 필요한 개념을 추상화하여 메서드나 프로퍼티 혹은 바인딩 메커니즘을 구현하게 된다. 예를 들어 데이터를 포맷팅하는 등의 Presentation 작업을 ViewModel에서 수행하여 View에게 전달해 줌으로써 View 코드를 단순하게 유지할 수 있게 된다.
Communication
MVVM 소통의 기본 규칙은 Model과 View가 반드시 ViewModel을 통해서만 상호작용 하는 것이며 전반적으로 단방향 참조 관계에 기반하여 데이터의 흐름과 호출 관계가 정의되어있다.
View - ViewModel 관계
View는 ViewModel을 소유한다. View에서 사용자 액션 등의 이벤트가 발생하면 ViewModel의 Intent 함수를 호출할 수 있다.
ViewModel은 Model의 변화를 감지하면 View에게 이벤트를 전달한다. 이때, View는 ViewModel의 메서드를 통해 데이터를 받아서 화면을 갱신한다.
ViewModel은 View와 참조 관계가 없기 때문에 바인딩 기술을 활용하게 된다.
ViewModel - Model 관계
ViewModel은 Model을 소유한다. ViewModel은 이벤트의 의도에 맞춰 Model을 수정할 수 있다.
ViewModel은 Model의 변화를 감지할 수 있다. Model 상태가 변동되면 ViewModel에게 상태가 변경되었음을 안내한다.
Model은 ViewModel과 참조 관계가 없기 때문에 바인딩 기술을 활용하게 된다.
Key Point
MVVM은 기존 MVC 아키텍처와 호환된다. MVC에서의 책임을 세부적으로 나눠주어 MVVM 구조로 리팩터링함으로써 View Controller를 가볍게 유지할 수 있게 되었다.
MVVM은 프로젝트를 테스트하기 쉬운 구조로 만드는데 도움 준다. 예를 들어 비즈니스 로직은 단위 테스트, View는 UI 테스트로 구분하여 테스트할 수 있다.
Advanced
Data Binding Technology
앞서 소개한 대로 MVVM은 단방향 참조 관계를 갖는다. Model과 View의 의존성을 최대한 분리하고 싶었기 때문이다. 따라서 Model의 상태가 변할 때 ViewModel을 통해 데이터를 View에 바인딩시키는 과정이 필요하며 다양한 기법을 통해 구현할 수 있다.
전통적인 방식으로는 KVO, Notification Center, Closure, Property Observer 등을 사용하는 방식을 생각해 볼 수 있다.
때로는 비동기 데이터 스트림을 활용한 Reactive Programming 기법을 활용하기도 한다. 대표적으로 Reactive X 혹은 Combine 기술을 생각해볼 수 있다. 함수형 패러다임의 API를 통해 비동기 이벤트를 손쉽게 가공할 수 있기도 하다.
References
' Apple > iOS Dev Challenges' 카테고리의 다른 글
[Challenge] 🛠️ iOS 앱 설계 퓨전 레시피 5부 - 계획과 목업 (0) | 2023.02.24 |
---|---|
[Challenge] 🛠️ iOS 앱 설계 퓨전 레시피 4부- Global Rule (0) | 2023.02.21 |
[Challenge] 🛠️ iOS 앱 설계 퓨전 레시피 2부 - MVC 디자인 패러다임 (0) | 2023.02.19 |
[Challenge] 🛠️ iOS 앱 설계 퓨전 레시피 1부 - 조감도 (0) | 2023.02.16 |
[Challenge] Cocoa Pods (0) | 2021.12.20 |