RxSwift #1 — RxSwift 시작하기

Kanghoon
10 min readJun 8, 2018

--

RxSwift 란?

‘RxSwift is a library for composing asynchronous and event-based code by using observable sequences and functional style operators, allowing for parameterized execution via schedulers.

By Marin Todorov. ‘RxSwift — Reactive Programming with Swift.’

RxSwift는 코드를 새로운 데이터에 반응하며 순차적으로 처리하게 함으로써 비동기 프로그래밍을 쉽게하도록 도와줍니다.

위의 말로만 보면 어렵죠.. 상황을 통해 살펴볼까요?

Q. 한 화면에서 3번의 네트워킹을 하여 각 데이터를 한 번에 표현하고자 한다면 어떻게 처리해야 할까요?

일반적인 방법으로는 GCD를 이용해서 처리했을 것 같습니다. 하지만 RxSwift를 사용한다면 더 쉽고 효과적으로 처리할 수 있습니다.

RxSwift 시리즈를 다 읽어보고 다시 이 문제를 어떻게 해결할지 생각해 봅시다.

시작하기에 앞서, RxSwift 를 이해하기 위한 기본적인 내용을 알아봅시다.

비동기 프로그래밍 (Asynchronous Programming)

대부분의 Class에서는 비동기로 작업을 수행하고 모든 UI 구성은 기본적으로 비동기로 처리하기 때문에 코드 전체가 어떤 순서로 실행되는지 가정하는 것은 불가능하다.

결국 코드는 사용자 입력, 네트워킹 등 다양한 외부 요인에 따라 다르게 실행된다. 앱을 실행할 때마다 외부 요인에 따라 코드가 완전히 다른 순서로 실행될 수 있다.

Apple은 비동기 코드를 작성하는 데 많은 API를 제공하고 있습니다.

지금까지 사용하던 것들

  • NotificationCenter : 사용자가 장치의 방향을 변경하거나 키보드가 등장하고 사라지는 것과 같이 이벤트가 발생할 때마다 코드를 실행합니다.
  • Delegate Pattern : 임의의 시간에 다른 클래스 나 API에 의해 실행될 메소드를 정의합니다. 예를 들어 Application Delegate에서 새 알림이 도착할 때 수행해야 할 작업을 정의하지만 이 코드가 언제 실행되는지 또는 실행될 지 알 수 없습니다.
  • Grand Central Dispatch (GCD) : 작품의 실행을 추상화하는 데 도움을 준다. Serial Queue에서 순차적으로 실행되도록 코드를 예약하거나 우선 순위가 다른 여러 Queue에서 동시에 많은 수의 작업을 실행할 수 있습니다.
  • Closure : 클래스간에 전달할 수있는 분리 된 코드. 각 클래스가 실행 여부를 결정할 수 있습니다. 어떤 상황에서 실행할지 결정할 수 있습니다.

하지만 API를 통한 복합적인 비동기 코드는 부분별로 나눠서 쓰기 매우 어렵다.

비동기 프로그래밍 용어들

RxSwift는 아래의 기본 용어를 먼저 이해하면 더 쉽게 이해할 수 있다.

1. State (Shared mutable state)

  • iOS 개발을 할 때 비동기 적인 State를 관리하는 것은 어렵습니다. 예를 들면 좋아요 기능을 구현한다고 했을 때 TabBar로 구성되어 있다면 한 화면에서 좋아요를 누르면 모든 탭에서 isLike의 상태가 바뀌어야 합니다.
  • 기존에는 Notification Center 를 사용해 이 문제를 해결했지만 RxSwift를 사용하면 더 쉽게 해결할 수 있습니다.

2. 명령형 프로그래밍 (Imperative programming)

  • 각각의 methods들이 하는 일을 알 수 없다.
  • 올바른 순서대로 methods 들이 작동할지 알 수 없다.

3. Side Effect

  • connectUIControls() 는 event Handler를 UI 구성 요소에 연결합니다. View의 state가 변경되면 Side Effect가 발생합니다.
  • SideEffect가 나쁜 것은 아니지만 컨트롤이 가능해야 한다.
  • 각 코드에 대해 어떤 코드가 SideEffect를 일으키는지, 단순히 데이터를 처리하고 출력하는지 알 수 있어야한다.

4. 선언적 코드(Declarative code)

  • 명령형 프로그래밍에서는 원하는대로 상태를 변경한다.
  • 함수형 코드에서는 Side Effect를 발생시킬 수 없다.
  • RxSwift에서는 명령형 프로그래밍과 함수형 코드를 결합하여 동작하게 한다.
  • 선언형 코드(Declarative code)로 동작을 정의할 수 있고, RxSwift는 관련 이벤트가 있을 때마다 동작을 실행하고 불변의 고유한 데이터 입력을 제공한다.
  • 이렇게하면 비동기 코드로 작업 할 수 있지만 단순 for문과 동일한 가정을 한다. 불변의 데이터로 작업하고 순차적이고 결정론적인 방식으로 코드를 실행할 수 있다.

5. Reactive Systems (반응형 시스템)

반응형 시스템은 다음과 같은 특성의 대부분을 나타내는 iOS 앱을 포함한다.

  • 반응 (Responsive): 항상 가장 최신의 State를 표시하며, UI를 최신 상태로 유지한다.
  • 복원력 (Resilient): 각각의 행동은 고유하게 정의되며 에러 복구를 위해 유연하게 제공한다.
  • 탄력성 (Elastic): 코드는 다양한 작업 부하를 처리하며, 종종 lazy pull기반 데이터 수집, Event throttling, 리소스 공유와 같은 기능을 구현합니다.
  • 메시지 기반 (Message driven): 구성 요소는 메시지 기반 통신을 사용하여 재사용 및 고유 기능을 개선하고, 라이프 사이클과 클래스 구현을 분리합니다.

RxSwift 기초

Rx 의 세가지 구성요소 : Observable, Operator, Schedulers

1. Observable

  • 데이터의 스냅샷을 전달할 수 있는 이벤트 시퀀스를 비동기적으로 생성하는 기능
  • RxSwift는 Observable을 통해 값을 배출할 수 있고, 이 값을 관찰하고 반응한다.
  • 하나 이상의 관찰자(Observer)실시간으로 어떤 이벤트에 반응하고 UI를 업데이트하거나 들어오는 데이터를 처리하고 활용할 수 있게 한다.

ObservableType 프로토콜

Observable은 세 가지 이벤트만 방출할 수 있다.

  • next : 최신(다음)값을 전송하는 이벤트
  • error : Observable이 값을 배출하다 에러가 발생하면 error를 배출하고 종료시키는 이벤트
  • complete : 성공적으로 이벤트 시퀀스를 종료시키는 이벤트. Observable이 더 이상 값을 배출하지 않음

Finite Observable Sequence

1개의 값을 방출하고 종료되는 시퀀스의 예제로 파일을 다운로드하는 코드를 살펴보자.

  1. 먼저 다운로드를 시작하고 데이터를 관찰한다
  2. 파일의 데이터를 받고 파일로 저장한다.
  3. 만약 네트워킹 연결이 끊기거나 시간 초과가 발생하면 에러가 발생한다
  4. 모든 데이터를 다운로드 하면 성공으로 완료
  • API.download(file:) 은 네트워킹 결과로 Data를 방출하는 Observable<Data>를 리턴한다.
  • onNext 클로저에서는 next 이벤트를 받아 처리할 수 있다. 예제에서는 다운로드한 데이터를 파일로 저장하게 될 것이다.
  • onError 클로저에서는 error 이벤트를 받아 처리할 수 있다. 예제에서는 에러 발생 로그를 처리할 것이다.
  • onCompleted 클로저에서는 completed 이벤트를 받아 처리할 수 있다. 예제에서는 다운로드 이후의 작업을 처리할 수 있다.

Infinite Observable Sequence

다운로드처럼 자연스럽게 종료되는 시퀀스와는 달리 무한히 관찰가능한 시퀀스도 존재한다. 보통 UI Event는 무한하게 관찰가능한 시퀀스이다. 앱의 기기 방향 변경에 대응하는 코드를 예제로 살펴보자.

  • RxSwift를 사용하지 않는다면 아래와 같이 NotificationCenter에서 UIDeviceOrientationDidChange 에 대한 알림을 받아 해결

이 부분을 RxSwift를 사용해서 해결해보자

  • UiDevice.rx.orientationObservable<Orientation>을 통해 만든 가상의 코드
  • orientationsubscribe하여 orientation의 값이 생성될 때마다 현재의 orientation을 받을 수 있고, 그 값을 이용해 UI를 업데이트할 수 있다.
  • 이 경우 onError, onCompleted는 절대 발생하지 않기 때문에 생략 가능

2. Operator

  • ObservableTypeObservable 클래스에는 복잡한 논리를 구현하기 위해 많은 메서드가 포함되어 있다. 이 메서드들을 Operator라고 부른다
  • Operator는 비동기 입력을 받아 출력만 생성하기 때문에 쉽게 결합 가능하다
  • Observable이 방출한 값에 Rx Operator를 적용하여 부수작용을 만들 수 있다.

위에서 다룬 방향전환 예제Rx Operator를 추가해보자

orientation.landscape 또는 .portrait 를 생성할 때마다, Rx는 방출된 데이터에 각각의 연산자를 적용한다.

  • 첫번째, filter.landscape가 아닌 값만 통과시킨다.
  • 두번째, .portrait 값이 들어온다면 map“portrait 입니다.” 출력으로 변환한다. (Orientation -> String)
  • 마지막으로, Subscribe를 통해 next이벤트를 구현. msg 값을 받아 print 한다.

3. Schedulers

  • Rx에서 SchedulerDispatch Queue와 같다. 다만 훨씬 쉽고 강력하다.
  • RxSwift에는 여러 Scheduler가 이미 정의되어 있어서, 개발자가 따로 자신의 스케줄러를 생성할 일은 드물다.
  • 기존에는 GCD를 이용해서 코드를 작성 했다면, Scheduler를 사용한 RxSwift에서는 다음과 같이 작동한다.

네트워킹을 예로 들어보자. 네트워킹에 필요한 작업은 아래와 같다.

  1. fetch JSON
  2. process JSON
  3. display UI
  • fetch JSON은 Custom Scheduler에서 구동된다.
  • 결과로 나온 JSON은 Background Concurrent Scheduler에서 process한다.
  • 이후, UI작업은 Main Thread Serial Scheduler에서 처리된다.

RxCocoa

RxCocoa는 RxSwift의 companion 라이브러리로, UIKit과 Cocoa 프레임워크 기반 모든 클래스를 가지고 있다. (RxSwift는 UIKit에 대한 정보가 없음)

RxCocoa를 사용하여 UIButton의 Tap 이벤트를 쉽게 확인할 수 있다.

이외에도 UIViewController, UITextView, UIWebView 등에 rx를 추가하여 사용할 수 있습니다.

--

--

Kanghoon
Kanghoon

No responses yet