원문 :  https://medium.cobeisfresh.com/implementing-mvvm-in-ios-with-rxswift-updated-for-swift-2-51cc3ef7edb3#.jzmyljsky

iOS에서 MVVM를 적용시키는 수많은 글들이 존재하지만, 실제로 사용되는 MVVM는 어떻게 생겼는지, 사실상 어떻게 하는지에 초점이 맞춰져있는 글은 거의 없다. 이 글은 RxSwift를 사용하여 좀 더 실질적인 관점에서 MVVM를 살펴 볼 것이다.

ReactiveX는 시퀸스를 observable 함으로서 비동기와 이벤트 기반 프로그램으로 구성된 라이브러리이다.— reactivex.io

RxSwift는 ReactiveX의 Swift 버전이다. 이것은 리엑티브하게 프로그래밍 할 수 있게 도와주는 프레임워크다. 만약 이게 무슨 말인지 모르겠어도(아마 그럴것이다. 함수형 리엑티브 프로그래밍(FRP)은 최근에 각광받기 시작했다.) 멈추지 말고 한번 읽어보길 추천한다. 리엑티브는 여러분의 프로젝트를 더 간결하고, 유지보수 하기 쉽고, 다루기 쉽게 만들어 줄 것이다.

어떻게 iOS 컴포넌트들이 서로 소통할까?
RxSwift의 가장 큰 부분은 앱에서 서로 다른 컴포넌트 사이에서 간단하게 소통할 수 있다는 점이다. 예를들어 Model과 ViewController가 있다. MVC에서는 이들을 연결하기 매우 난잡함을 느낄 수 있었을 것이다.

ViewController에서 모든 outlet을 리셋시키기위해, 아마 model이 갱신될때 항상 Controller에서 updateUI() 함수를 호출해주어야 할 것이다. 이러한 흐름은 불필요한 갱신이나 이상한 버그들이 생기면서 Model과 ViewController 사이에 부조화가 일어나기 쉽다.

우리는 매 순간마다 Model의 옳바른 상태를 표시하는 View Controller가 필요하다. Model이 어떻든 Model 갱신되는 즉시 일치한 데이터를 보여주는 View Controller가 필요하다.

물론 바로 Model만 표시하는 대부분의 앱에서는 의미없는 고민이겠지만, 우리는 Model로부터 데이터를 뽑아와서 화면에 표시할 준비를 하는 과정이 필요하다. 이것이 왜 ViewModel 클래스를 소개하게 되었는지에 대한 이유이다. ViewModel은 화면에 표시할 모든 데이터를 준비한다.

그러나 조금 재미있는 부분이 있다: ViewModel은 ViewController에대해 아무것도 모른다는 사실이다. 절때 그 안에서 직접적으로 참조하거나 프로퍼티를 가지고 있지 않는다. 대신에 ViewController는 ViewModel의 모든 변화를 항상 Observe하고 있으며, ViewModel에서 변화가 일어나면 그것을 화면에 표시한다.

한 프로퍼티당 기반임을 기억하고 있자. 이 의미는 ViewModel 안에서 ViewController가 화면에 개별적으로 각 프로퍼티를 표시한다. 예를들어, 문자열과 이미지를 불러올때, 그 두가지를 다 불러올 때까지 기다리고 있는 것이 아니라, 불러와지는데로 바로바로 각 이미지를 화면에 표시할 수 있다.

ViewController는 화면에 표시하는 역할 뿐 아니라 유저의 입력을 받는 역할도 한다. 우리 ViewController는 단지 프록시(proxy)이고, 그 입력을 ViewController에서 따로 사용하지 않으므로 모든것을 ViewModel로 보내버리고 이것을 ViewModel이 알아서 처리할 것이다.

위 그림은 ViewController와 ViewModel 사이에 단방향 통신을 하는 방법이다. ViewController는 ViewModel을 보고 그것에게 말할 수 있지만, ViewModel은 ViewController가 무엇인지 전혀 모른다. 이 말은 앱에서 ViewController를 완전히 제거해도 모든 로직이 제대로 동작할 것이라는 뜻이다!

좋아보이지 않는가?! 그러나 어떻게 이게 가능할까?

RxSwift와 함께 MVVM
유저의 도시 입력에 따른 기상 예측을 표시해주는 간단한 날씨 앱을 만들어보자.

이 글은 RxSwift의 기본 지식을 가정하고 쓰였다. 만일 ReactiveX에 대해 전혀 모른다면, 마음가는대로 읽어도 상관없지만, ReactiveX 글을 읽어보길 추천한다.


우리는 도시 이름을 입력받기 위해 UITextFeild를 준비하고 현재 온도를 보여주기위해 UILabel을 준비했다.

Note: 이 앱에서는 OpenWeatherMap의 날씨 데이터를 사용했다.

도시의 이름과 날씨로 구성된 Weather 구조체가 우리의 Model이 될 것이다. 이 구조체는 받아온 값을 파싱한 뒤, 속성에 맞춰 만들어진 JSON 오브젝트로부터 만들어진다.


이제 public의 searchText 프로퍼티가 변경될 때, ViewModel이 새 Model을 요청해야한다. ViewController는 유저 입력을 보내기 위해 이 프로퍼티에 접근하게 된다.

searchText는 변수이다. 변수는 필수적으로 BehaviorSubject를 감싼다. 이것은 Observer할수도, Observable할수도 있다. 다시말해 그들이 다시 호출할 수 있는 항목을 그들에게 보낼 수 있다.

BehaviorSubject는 한번만 구독되야하기 때문에 유일한 존재이다. BehaviorSubject는 받았던 마지막 항목을 보낸다. MVVM에서는 이러한 방식이 필요하다. 앱의 라이프 사이클에 의존하며, 다른 클래스에서 Observable은 종종 그것들을 구독하기 전에 엘리먼트를 받기도 한다. ViewController가 ViewModel의 프로퍼티에 구독하면, 화면에 표시하기위해 마지막 항목이 무엇인지 보아야한다. 반대의 경우도 마찬가지이다.

이제 우리는 프로그래밍적으로 변하는 모든 UI 부분에 대해 ViewModel 안에 한 프로퍼티를 정의할 것이다.

ViewModel은 데이터를 출력할 수 있는 형태로 변환하는 역할을 맡고 있다. 이 경우 우리의 Model은 다른 Weather 객체의 Observe되어지는 한 순서이다. 위 프로퍼티(cityName, degrees)는 Weather Observable에 다른 맵핑이 일어날 것이다.

이 프로퍼티가 private로 선언된 이유를  기억하자. ViewController에는 비즈니스 로직에 대해 전혀 몰라야 하기 때문이다. ViewController는 화면에 표시하기 위한 데이터 밖에 모른다.

검색
이제 우리가 위에서 선언한 searchText 프로퍼티에 우리의 Model을 연결해보자.

우리는 searchText가 바뀔때마다 네트워크 요청을 만들 것이다. 그리고 우리의 Model은 그 요청을 구독하고 있을 것이다.

이 경우 searchText가 바뀔때마다 jsonRequest는 NSURLRequest와 통신하기 위해 스스로 갱신된다. 갱신마다 우리의 Model은 NSURLRequest로부터 어떤것을 받던지간에 세팅된다.

만약 JSON 요청중 에러가 나오면 그것을 출력하고 빈 값을 반환한다.

Note: rx_JSON() 메소드는 실제로 그 스스로 Observable 순서이다. 그러므로 jsonRequest는 Observable의 Observable이다. jsonRequest가 가장 최신의 것을 리턴하기 위함이 마지막에 .switchLatest()를 사용하는지에대한 이유이다. 또한 요청을 당신이 그것에 구독하기 전까지 패치되지 않을 것이라는 것을 기억해두자.

.shareReplayWeather에 구독하는 모든 것들이 정확하게 같은 결과를 받았는지 확신하기 위함이다. 그렇지 않을 경우 각 구독은 날씨의 개별 객체를 호출할 것이고 요청이 중복으로 일어날 수 있기 때문이다.

이제 남은 것은 ViewController를 ViewModel에 연결하는 것이다. ViewModel의 Observable을 Controller의 outlet에 바인딩하여 연결할 수 있다.(We’ll do this by binding the PublishSubjects in the ViewModel to outlets in the Controller.)

사용자가 텍스트 필드에 친 값을 ViewModel이 알고 있어야함을 기억하자! ViewModel의 searchText 프로퍼티에 ViewController의 textField 값을 바인딩하여 위 일을 할 수 있다. 따라서 viewDidLoad()에 아래의 코드만 추가하면 된다:


이제 됐다! 우리 앱은 유저가 타이핑하는 동안 날씨 데이터를 갱신한다. 그리고 유저가 어떤 것을 볼지라도 화면 뒤의 앱 상태를 보게된다.

이 앱에서 좀 더 확장되고 주석이 달린 코드의 버전에 관심이 있다면 내 Github의 Weather 앱을 확인해보아라.


여기 당신이 흥미있어할 법한 더 많은 글들이 있다.


용어 정리

  1. Observable, Observer, Subscribe
    : 옵저버 디자인 패턴에서 사용하는 용어로, Observer는 구독(Subscribe)하는 오브젝트, Observable은 구독당하는 오브젝트를 말한다. Observer는 
    Observable에게 자기 자신을 넘겨줘서 Observable에서 이벤트가 발생할때 Observer에 있는 메소드를 호출해줌으로서 구독할 수 있다. 이 글에선 Observer나 Observable에 적합한 한글번역을 찾지 못해, 그대로 표기하였다.



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,