RxSwift로 반응형 프로그래밍하기

Reactive Programming with RxSwift라는 주제로 지난 Swift Korea Meetup에서 발표된 내용입니다.


소개

저는 현재 Trust Us에서 포잉을 개발하고 있는 이선협입니다. GitHub에서 만나볼 수 있습니다.

작년에 Functional Reactive Programming이라는 주제로 발표한 내용을 토대로 이번 강연을 진행하겠습니다.

Reactive Programming

Reactive는 반응을 보인다는 뜻입니다. 일반 명령형 프로그래밍과 차이를 살펴볼까요?


// 명령형 프로그래밍
b = 27
c = 33
a = b + c
print(a) // 60
c = 40
print(a) // 60

// 반응형 프로그래밍
b = 27
c = 33
a = b + c
print(a) // 60
c = 40
print(a) // 67

명령형 프로그래밍은 a에 값을 정한 이후 c의 값이 바뀌더라도 a의 값이 바뀌지 않지만, 반응형 프로그래밍은 c의 값이 변하는 것에 반응하여 a의 값이 바뀌는 형태입니다. 실제로 위 예제와 같은 코드를 짜게 되지는 않지만 이런 식의 형태라고 이해하시면 좋습니다. Wikipedia에서도 볼 수 있듯 반응형 프로그래밍을 대표하는 프로그래밍은 엑셀입니다.

RxSwift

RxSwift는 Swift에서 반응형 프로그래밍을 하기 위한 라이브러리입니다. 왜 RxSwift가 많은 인기를 얻고 있을까요? RxSwift의 장점을 위주로 설명하겠습니다.

이런 개발 뉴스를 더 만나보세요

Observable

옵저버블은 Hot / Cold 두 가지로 분류됩니다. Hot 옵저버블은 평소에 자주 사용하는 옵저버 패턴과 비슷합니다. 옵저버블에 이벤트가 발생하면 이를 구독하는 구독자가 이벤트를 받을 수 있습니다. 하지만 구독자가 없는 경우라도 Hot 옵저버블은 이벤트를 계속 발송합니다. 즉, Facebook Live처럼 보는 사람이 없더라도 계속 방송을 합니다. 반면, Cold 옵저버블은 구독자가 없는 경우라면 이벤트를 전달하지 않습니다. 즉, 일반 VOD 서비스처럼 보는 사람이 없으면 방송을 송출하지 않습니다. Hot 옵저버블을 Eager Evaluation, Cold 옵저버블을 Lazy Evaluation이라고 부르기도 합니다.

Data Flow

데이터 플로우는 개발자가 흔히 사용하는 컨트롤 플로우 방식과 달리 말 그대로 데이터가 흐르는 방식의 패러다임입니다. 체이닝 등을 통해 구현할 수 있습니다.

예제

RxSwift의 핵심 개념은 이런 옵저버블과 데이터 플로우입니다.

just라는 오퍼레이터를 사용했습니다. just로 감싼 문자열을 옵저버블로 만드는 메서드입니다. 다음으로 subscribe는 앞서 만든 옵저버블을 구독합니다. 이렇게 구독을 한 후 Lazy Evaluation으로 값을 받아옵니다. print에서는 “Hello, World!”가 찍히겠죠? addDisposableTo는 시퀀스를 중단하는 메서드입니다.

subscribeDisposable이라는 객체를 반환하는데, dispose()라는 메서드를 호출해서 시퀀스를 중단하거나, DisposeBag이라는 객체에 담아서 한꺼번에 시퀀스가 종료되도록 사용할 수 있습니다. DisposeBag에 담을 때는 스레드 간에 충돌이 나지 않도록 SpinLock이 돕니다.

RxSwift의 장점

이제 본격적으로 RxSwift의 장점에 관해 설명하겠습니다.

비동기/이벤트의 스트림

RxSwift의 가장 큰 장점은 비동기와 이벤트가 스트림으로 흐른다는 점입니다. 상황별로 살펴보겠습니다.

SNS 서비스 앱을 만드는 회사에서 ‘내 정보 화면’을 작성하는 경우를 생각해 보겠습니다. 이 화면에는 개인 정보, 사진첩, 친구 목록, 타임라인, 총 4가지 데이터가 필요하며 자연스럽고 모든 정보를 한 번에 바인딩하고자 합니다. 또한, 이 페이지에 접근하는 경우 토큰이 유효한지도 확인해야 합니다. 어떻게 처리해야 할까요?

벌써 콜백 지옥, 더티플래그, 수많은 if들이 필요할 것 같습니다. 하지만 창시자인 MicroSoft에서 Rx를 다수의 비동기 이벤트 처리를 위해 만들었고 할 만큼, Rx는 비동기 이벤트를 효과적으로 처리할 수 있습니다.

앞서 설명한 스트림을 그림으로 표현해 봤습니다. 코드로 만들면 다음과 같습니다.

먼저 토큰의 유효성을 확인하고 flatmap으로 옵저버블 언래핑 후, zip으로 여러 이벤트를 한 번에 묶고 모든 이벤트가 끝났을 때 한 번에 가져올 수 있도록 합니다. 그다음 subscribe를 하는 코드가 이어집니다. 이 과정에서 에러가 발생하면 onError로 빠집니다.

이렇게 ‘내 정보 화면’을 성공적으로 처리하고 난 후 타임라인에 ‘좋아요’ 기능을 추가하려면 어떻게 코드를 짜야 할까요? UI 이벤트를 처리해야 하는 작업이죠.

스토리보드를 사용하면 @IBAction을 사용할 수 있겠지만, 성능상의 문제로 사용하지 않았고, 코드로 작성해도 관리 포인트가 두 군데가 생기므로 사용하지 않았습니다. 결론적으로 Rx를 사용하기로 했습니다.

like 버튼에 rx.tap을 통해 이벤트를 스트림으로 만들고, flatMap으로 옵저버블 언래핑 후 API 호출을 통해 다른 데이터의 형태로 반환했습니다. 즉, 이벤트가 데이터로 흘러서 API로 변환된 것입니다. 이 두 가지 코드 모두 이벤트의 스트림을 사용해서 깔끔하게 다른 형태로 변경할 수 있습니다.

다양한 오퍼레이터

RxSwift의 다른 장점은 오퍼레이터가 다양하다는 점입니다. 비동기 처리에 특히 유용한 오퍼레이터들이 많고 사용법을 번역된 페이지도 있습니다.

Rx 오퍼레이터 중 throttle을 사용한 코드로, Cocoa 프레임워크를 미리 구현해둔 RxCocoa를 함께 사용한 예제입니다. 코드가 Swift 2 버전임을 양해해 주세요. 검색을 할 때 테이블뷰에 데이터를 바인딩하는 기능을 하고 있습니다.

rx_text는 RxCocoa의 익스텐션 프로퍼티입니다. throttle은 지정한 시간 동안 생긴 옵저버블 아이템 중 마지막 것을 선택해주는 오퍼레이터입니다. flatMap은 flatten과 map을 합친 오퍼레이터로 옵저버블을 언래핑해주는 오퍼레이터입니다. 키보드에서 가져온 쿼리를 WasManager로 넘겨서, 과정에서 에러가 있으면 빈 값을 반환합니다. WasManager는 네트워크 데이터를 옵저버블로 만들어서 반환하는 클래스로 직접 만들었습니다. 또한, 테이블뷰에 데이터를 바인딩해주도록 bindTo를 사용했습니다.

편한 스레드 관리

일반적으로 옵저버블의 흐름은 직렬적으로 이뤄지지만, 병렬적으로 이뤄지는 경우 zip이나 merge 등의 오퍼레이션을 사용하면 편합니다.

위의 스레드 사용 예제를 살펴보면, 두 가지 옵저버블이 있는데 observable1은 0부터 천만까지의 합을 구하는 옵저버블이고, observable2는 문자열을 옵저버블로 만들었습니다. 이 둘을 zip 오퍼레이터로 합치는 경우 오랜 시간이 걸리는 observable1이 끝나기 전에는 zip이 실행되지 않습니다. 따라서 맨 밑의 “Hello”는 굉장히 오랜 이후에 실행됩니다. 따라서 reduce를 백그라운드에서 실행해야 합니다.

subscribeOn(backgroundScheduler)라는 한 줄만 추가하면 reduce를 백그라운드에서 실행할 수 있습니다. 하지만 subscribe 영역도 백그라운드에서 처리되므로 UI 바인딩이 메인 스레드에서 이뤄질 수 없습니다. 이럴 때는 observerOn(MainScheduler.instance)로 해결할 수 있습니다.

정리

지금까지 RxSwift의 장점인 비동기/이벤트 스트림과 다양한 오퍼레이터, 편한 스레드 관리 등을 설명했습니다. 많은 분이 RxSwift의 장점을 느끼고 사용을 시작하시는 데 도움이 됐으면 좋겠습니다. 마지막으로 ReactorKit 라이브러리를 추천하고 싶습니다. Flux와 반응형 프로그래밍을 결합한 라이브러리로, Flux를 iOS에 도입하고 싶은 분들께 꼭 맞는 라이브러리입니다.


본 영상과 글은 Swift Korea Meetup의 비디오 스폰서인 Realm에서 제공합니다. 모바일 개발자가 더 나은 앱을 더 빠르게 만들도록 돕는 Realm 모바일 데이터베이스Realm 모바일 플랫폼을 통해 핵심 로직에 집중하고 개발 효율을 높여 보세요! 공식 문서에서 단 몇 분 만에 시작할 수 있습니다. 또한 Realm 홈페이지에서는 모바일 개발자를 위한 다양한 최신 기술 뉴스와 튜토리얼을 제공하고 있으니 즐겨찾기하고 자주 들러 주세요!

다음: RxSwift 예제로 감잡기 : RxSwift 시작을 위한 간단한 예제들

General link arrow white
`

이선협

Trus Us (포잉)에서 일하는 이선협입니다. GitHub에서 만나볼 수 있습니다.

기록 Eunjoo Im