티스토리 뷰

RxSwift 시작하기

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는 코드를 새로운 데이터에 반응하며 순차적으로 처리하게 함으로써 비동기 프로그래밍을 쉽게하도록 도와준다.

UIKit에서의 비동기 프로그래밍

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

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

Apple은 iOS SDK 내에서 비동기 코드를 작성할 수 있도록 다양한 API를 제공하고 있으며 주된 방법들은 다음과 같다.

  1. Notification Center
  2. delegate pattern
  3. Grand Central Dispatch(GCD)
  4. Closures

문제는, Apple의 SDK내의 API를 통한 복합적인 비동기 코드는 부분별로 나눠서 쓰기 매우 어려울 수 밖에(또는 거의 추적불가능) 없다는 것.

비동기 프로그래밍 용어들

1. State, and specifically, shared mutable state

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

앱의 State(상태)를 관리하는 것(특히 여러가지 비동기 구성요소를 공유할 때)은 RxSwift를 통해 배울 수 있는 중요한 포인트 중 하나

2. 명령형 프로그래밍
명령형 프로그래밍이란 선언형 프로그래밍과 반대되는 개념으로, 프로그래밍의 상태와 상태를 변경시키는 구문의 관점에서 연산을 설명하는 프로그래밍 패러다임의 일종이다.

  • 명령형 프로그래밍은 강아지와 노는 것과 비슷하다.(물어와!, 앉아!, 빵!)
  • 앱에게 정확히 '언제' '무엇을' 하라고 말하고 싶을 때 명령형 코드를 쓸수있다.
  • 컴퓨터가 이해하고 있는 방식과도 비슷하다. 예를 들어서 모든 CPU는 간단한 명령어으로 이루어진 긴 sequences를 따른다.
  • 문제는 인간이 복잡하고 비동기적인 앱을 만들기 위해 명령형 코드를 사용하는 것이 너무나 어렵다는 점!
  • 예를 들어 iOS ViewController의 viewDidAppear(_:)를 확인해 보자.
 override func viewDidAppear(_ animated: Bool) {
     super.viewDidAppear(animated)

     setupUI()
     connectUIControls()
     createDataSource()
     listenForChanges()
 }
  • 위의 코드만 봐서는 각각의 method들이 무슨 동작을 하는지 전혀 알 수 없다.
  • 실수로 method의 순서를 바꿨다면 이로 인해 앱이 다르게 작동되어 버릴수도 있다.(올바른 순서대로 methods 들이 작동할지 알 수 없다.)

3. Side Effect(부(수)작용들)

  • Side Effect란 현재 scope외 상태에서 일어나는 모든 변화를 뜻한다.
  • 위의 예시 코드에서 connectUIControls()는 eventHandler를 UI구성 요소에 연결한다. View의 state가 변경되면 이때 Side Effect가 발생한다.
  • 예를 들면 스크린 상 labeltext를 추가하거나 변경한다는것. -> 디스크에 저장된 데이터를 수정한다는 것 -> Side Effect가 발생한다는것.
  • Side Effect가 나쁜것은 아니지만 컨트롤이 가능해야 한다.
  • 해당 코드가 어떤 Side Effect를 발생시킬 수 있는 코드인지, 단순히 데이터를 처리하고 출력하는지 알 수 있어야한다.

RxSwift는 이러한 이슈를 추적가능하게 해준다.

4. 선언형 코드(Declarative code)

  • 명령형 프로그래밍에서의 상태 변화는 자유자재로 가능하다.
  • 함수형 코드에서는 Side Effect를 발생시킬 수 없다.
  • RxSwift는 이 두 가지를 결합하여 동작하게 한다.
    • 명령형 프로그래밍 + 함수형 프로그래밍
    • 자유로운 상태변화 + 추적/예측 가능한 결과값
  • 선언형 코드(명령형과 반대)를 통해 동작을 정의할 수 있으며, RxSwift는 관련 이벤트가 있을 때 마다 이러한 동작을 실행하고 작업할 수 있는 불변의 고유한 데이터 입력을 제공한다.
  • 이렇게 하면 불변의 데이터로 작업하고 순차적이고 결정론적인 방식으로 코드를 실행 할 수 있다.

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

반응형 시스템 이란 의미는 상당히 추상적이며, 다음과 같은 특성의 대부분 또는 전부를 나타내는 iOS 앱을 다루게 된다.

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

RxSwift 기초

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

1. Observable

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

ObservableType 프로토콜

  • Observable은 세 가지 이벤트만 방출할 수 있다.
  • next: 최신(다음) 값을 전송하는 이벤트.
  • error: Observable이 값을 배출하다 에러가 발생하면 error를 배출하고 종료 시키는 이벤트.(이벤트 더이상 생성하지않음, 에러와 함께 완전종료)
  • complete: 성공적으로 이벤트 시퀀스를 종료시키는 이벤트, Observable이 더이상 값을 배출하지 않는다.
  • 아래의 그림처럼 시간에 걸쳐 발생되는 비동기 이벤트를 예시로 들어보자.

  • 시간에 따라 이미지의 Int값들이 전달되었다.
  • 해당 Observable을 Observer1, 2, 3 이 구독(subscribe)하고 있다면 시간에 따라 전달된 Int 데이터를 전달받아 사용할수 있게되는것이다.
  • 시간에 따라 전달된 Int값을 활용하기 위해서는 전달받았을때 어떤 행동을 할것인지 혹은 보여줄것인지를 정의해두면 된다!

Finite observable sequences

  • 어떤 Observable sequence는 0, 1ㄷ 또는 다른 값을 방출한 뒤, complete 또는 error를 통해 종료된다.
  • 1개의 값을 방출하고 종료되는 시퀀스의 예제로 파일을 다운로드 하는 코드를 살펴보자.
    1. 먼저 다운로드를 시작하고 데이터를 관찰한다.
    2. 파일의 데이터를 받아 파일로 저장한다.
    3. 만약 네트워킹 연결이 끊기거나 시간 초과가 발생하면 에러가 발생한다.
    4. 모든 데이터를 다운로드 하면 성공으로 완료.
API.download(file: "http://filePath....")
    .subscribe(onNext: { data in
        // 다운로드한 데이터를 파일로 저장
    }, onError: { error in
        // 다운로드 에러 발생
    }, onCompleted: {
        // 다운로드 완료
    })
  • API.download(file:)은 네트워킹 결과로 Data를 방출하는 Observable를 반환한다.
  • onNext 클로저를 통해 next 이벤트를 받을 수 있다. 예제에서는 받은 데이터를 디스크의 temporary file에 저장하게 될 것이다.
  • onError 클로저를 통해 error 이벤트를 받을 수 있다. alert 메시지 같은 action을 취할 수 있을 것이다.
  • 마지막으로 onCompleted 클로저를 통해 completed이벤트를 받을수 있으며, 이를 통해 새로운 ViewController를 push하여 다운로드 받은 파일을 표시하는 등의 액션을 취할 수 있을 것이다.

Infinite Observable Sequence

  • 위의 예시 다운로드 처럼 종료되는 시퀀스와 달리 무한히 관찰 가능한 시퀀스도 존재한다.
  • 보통 UI Event는 무한하게 관찰가능한 시퀀스다.
  • 앱의 기기 방향 변경에 대응하는 코드를 예제로 살펴보자.
  • RxSwift를 사용하지 않는다면 아래의 코드와 같이 NotificationCenter 에서 UIDeviceOrientationDidChange에 대한 알림을 받아 해결할수있다.
NotificationCenter.default.addObserver(self,
                                       selector: #selector(rotated),
                                       name: NSNotification.Name.UIDeviceOrientationDidChange,
                                       object: nil)
func rotated() {
    if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
        print("landscape 상태")
    }

    if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
        print("portrait 상태")
    }

}

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


UIDevice.rx.orientation
  .subscribe(onNext: { current in
    switch current {
      case .landscape:
        print('landscape 상태')
      case .portrait:
        print('portrait 상태')
    }
  })
  • UIDevice.rx.orientationObservable<Orientation>을 통해 만든 가상의 코드다.
  • orientation을 Subscribe(구독)하여 orientation의 값이 생성될 때마다(예제에서는 디바이스의 방향이 변경될때마다) 현재의 orientation 을 받을수 있고, 그값을 이용해 UI를 업데이트할 수 있다.
  • 이 경우 onError, onCompleted는 발생하지 않기 때문에 생략 가능하다.

Operator

  • ObservableTypeObservable클래스에는 복잡한 논리를 구현하기 위해 많은 메서드가 포함되어있으며 이를 Operator라고 부른다.
  • Operator는 비동기 입력을 받아 출력만 생성하기 때문에 쉽게 결합 가능하다.
  • Observable이 방출한 값에 Rx Operator를 적용하여 부수작용을 만들 수 있다.
  • 위의 방향전환 예제에 Rx Operator를 추가해보자.
UIDevice.rx.orientation
  .filter { $0 != .landscape }
  .map { _ in
    return "portrait 입니다."
  }
  .subscribe(onNext: { msg in
    print(msg)
  })
  • orientation.landscape또는.portrait을 생성할 때 마다, Rx는 방출된 데이터에 각각의 연산자를 적용한다.
  • 첫번째, filter는 .landscape가 아닌 값만 통과시킨다.
  • 두번째, .portrait 값이 들어온다면 map은 “portrait 입니다.” 출력으로 변환한다. (Orientation -> String)
  • 마지막으로, Subscribe를 통해 next이벤트를 구현. msg 값을 받아 print 한다.

Schedulers

  • Rx에서 SchedulerDispatch Queue와 동일한것. 훨씬 쉽고 강력하다.
  • RxSwift에는 여러 Scheduler가 정의 되어있으며, 개발자가 따로 자신의 스케줄러를 생성할일은 드물다.
  • 기존에는 GCD를 이용해서 코드를 작성 했다면, Scheduler를 사용한 RxSwift에서는 다음과 같이 작동한다.
  • 네트워킹을 예로 들어보자. 네트워킹에 필요한 작업은 아래와 같다.
      1. fetch JSON
      1. process JSON
      1. display UI
  • fetch JSON은 Custom Scheduler에서 구동된다.
  • 결과로 나온 JSON은 Background Concurrent Scheduler 에서 process한다.
  • 이후 UI작업은 Main Thread Serial Scheduler 에서 처리된다.

App Architecture

  • RxSwift는 기존의 앱 아키텍처에 영향을 주지 않는다. 주로 이벤트나 비동기 데이터 시퀀스 등을 주로 처리하기 때문이다.
  • 따라서 apple 문서에 언급된 MVC 아키텍처에 Rx를 도입할 수 있다. MVP, MVVM 에서도 가능하다!
  • Reactive App을 만들기 위해 처음부터 프로젝트를 시작할 필요도 없으며, 기존 프로젝트를 부분적으로 리팩토링하거나 단순히 앱에 새로운 기능을 추가할 때도 사용가능하다.
  • Microsoft의 MVVM아키텍쳐는 데이터 바인딩을 제공하는 플랫폼에서 이벤트 기반 소프트웨어용으로 개발되었기 때문에, RxSwift와 MVVM은 같이 쓰기 좋은 예다.
    • ViewModel을 사용하면 Observable<T>속성을 노출할 수 있으며 ViewController의 UIKit에 직접 바인딩이 가능하다.
    • 이렇게 하면 모델 데이터를 UI에 바인딩하고 표현하고 코드를 작성하는 것이 매우 간단해진다.(ViewController의 코드가 굉장히 줄어든다!)
  • 아래의 이미지는 MVVM과 RxSwift의 예시 이미지이다.

    ViewModel의 모델데이터를 ViewController에서 바인딩만 해주면된다!

RxCocoa

  • RxCocoa는 RxSwift의 동반 라이브러리로, UIKit과 Cocoa 프레임워크 기반 개발을 지원하는 모든 클래스를 보유하고 있다.
    • RxSwift는 일반적인 Rx API라서, Cocoa나 특정 UIKit 클래스에 대한 아무런 정보가 없다.
  • 예를 들어, RxCocoa를 이용하면 UISwitch의 상태를 확인하는 것은 예제코드와 같이 매우쉽다.
 toggleSwitch.rx.isOn
     .subscribe(onNext: { enabled in
         print( enabled ? "It's ON" : "it's OFF")
     })
  • RxCocoa는 rx.isOn과 같은 프로퍼티를 UISwitch클래스에 추가해주며, 이를 통해 이벤트 시퀀스를 확인할 수 있다.
  • RxCocoa는 UITextField, URLSession, UIViewController 등에 rx키워드를 추가하여 사용한다.

참고한 문서및 자료

https://github.com/fimuxd/RxSwift/blob/master/Lectures/01_HelloRxSwift/Ch.1%20Hello%20RxSwift.md
https://okanghoon.medium.com/rxswift-1-rxswift-%EC%9E%85%EB%AC%B8-67bfdbd91969

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함