RxSwift #2 — Observable 과 Subject (+ Relay) 알아보기

Kanghoon
10 min readAug 3, 2018

--

이번에는 앞선 글에서 다룬 Observable를 시작으로, Observer인 Subject, RxCocoa의 Relay 세가지에 대해 알아보려고 합니다.

먼저 이전 글에서 다룬 Observable에 대해 더 자세히 알아봅시다.

Observable

Observable은 이벤트 시퀀스를 비동기적으로 생성하는 기능을 가지고 있습니다.이 때 Observable이 지속적으로 이벤트를 발생시키는 것을 emit 이라고 합니다.

1. Observable의 LifeCycle

RxSwift: Reactive Programming with Swift book

next를 통해 1, 2, 3을 방출하는 Observable

RxSwift: Reactive Programming with Swift book

세 번의 tap 이벤트를 방출한 뒤 complete 를 통해 종료된 Observable

RxSwift: Reactive Programming with Swift book

1, 2를 방출하고 에러가 발생해 error 를 통해 종료된 Observable

이전 글에서 다뤘던 내용을 정리해보면 아래와 같습니다.

next : 최신(다음)값을 전송하는 이벤트

error : Observable이 값을 배출하다 에러가 발생하면 error를 배출하고 종료시키는 이벤트

complete : 성공적으로 이벤트 시퀀스를 종료시키는 이벤트. Observable이 더 이상 값을 배출하지 않음

2. Observable의 생성

let observable: Observable<Int> = Observable<Int>.just(1)
  • just는 오직 하나의 요소를 포함하는 Observable Sequence를 생성
let observables = Observable.of(1, 2, 3)
  • of는 주어진 값들에서 Observable Sequence를 생성
let observables2 = Observable.of([1, 2, 3])
  • of의 인자로 array를 넣게되면 [1, 2, 3]을 단일요소로 가지게 됩니다
  • observables2 의 타입은 Observable<[Int]>
let observables3 = Observable.from([1, 2, 3])
  • from을 사용하게 되면 array의 요소들로 Observable Sequence 생성
  • observables3 의 타입은 Observable<Int>

3. Subscribing ( 구독 )

ObservableSequence의 정의일 뿐이다. Subscribe 되기 전에는 아무런 이벤트도 보내지 않습니다.

  • .subscribe는 escaping 클로저로 Event<Int>를 갖는다. escaping에 대한 리턴값은 없으며 Disposable을 반환합니다.
  • Prints를 보면 observable은 각 요소들에 대해서 .next 이벤트를 방출합니다.
  • 마지막으로 .completed를 방출합니다.

4. subscribe(onNext: , onError:, onCompleted:, onDisposed:)

  • Observable이 방출하는 .next, .error, .completed 각각의 이벤트들에 대해 subscribe 연산자가 있습니다.
  • 위에서 사용한 subscribe()은 아래와 같이 사용할 수 있습니다.

onNext 클로저는 .next 이벤트 만을 핸들링하고, onCompleted 클로저는 .completed 만을 핸들링 합니다

5. 여러가지 Observable

지금까지 한개 혹은 여러개의 Element를 가진 Observable을 만들었습니다. 이제 더 다양한 Observable을 살펴봅시다.

.empty()

  • .empty 는 요소를 하나도 가지지 않는 Observable을 생성합니다. 따라서 .completed 이벤트만을 방출하게 됩니다.
  • 즉시 종료할 수 있는 Observable을 리턴하고 싶을 때 사용합니다.

.range()

  • .range 는 start 부터 count 까지의 값을 갖는 Observable 을 생성하다.

6. Disposing

subscribing은 Observable이 이벤트들을 방출하도록 해주는 방아쇠 역할을 한다면 반대로 disposing은 구독을 취소하여 Observable을 수동적으로 종료시킵니다.

.dispose()

  • Int 의 Observable을 생성하고 subscribe을 통해 Disposable을 반환
  • 구독을 취소하고 싶으면 dispose()를 호출하면 됩니다.

DisposeBag()

  • 각각의 구독에 대해서 일일히 관리하는건 효율적이지 못하기 때문에 RxSwift 에서 제공하는 DisposeBag을 사용할 수 있습니다.
  • Disposable은 DisposeBag instance 의 deinit() 이 실행될 때 dispose()를 호출합니다.

.create(:)

Observable을 .create 연산자로 만드는 방법이 있습니다.

  • .create 는 escaping 클로저로 AnyObserver<T> 를 인자로 받아 Disposable을 반환합니다.
  • .next(“1”), .completed, .next(“2”)의 이벤트를 가진 Observable 을 생성하고 Disposable을 반환합니다.
  • 여기서 .next(“2”) 의 경우 onComplete 이후이기 때문에 방출되지 않습니다.

7. Traits

Trait은 일반적인 Observable보다 좁은 범위의 Observable

# 종류 : Single, Maybe, Completable

Single

무한한 이벤트 스트림이 아닌 하나의 결과, 에러를 처리하고자 할 때 사용

  • .success(value) or .error 만을 방출합니다.
  • .success(value).next.completed 이벤트의 조합
  • HTTP 요청처럼 한 번의 응답 / 에러를 처리할 때 사용합니다

Completable

결과값이 필요하지 않고 완료만 의미 있는 모델에서 사용

  • .completed or .error 만을 방출합니다.
  • 연산이 성공적으로 완료되었는지 확인하고 싶을 때 사용합니다.

Maybe

Single 과 Completable을 섞어 놓은 것

  • .success(value) , .completed , .error 를 방출합니다
  • 하나의 이벤트가 발생하거나, 이벤트 없이 완료 되거나, 에러가 발생하거나 셋 중 하나의 결과를 발생시키고 종료됩니다
  • Observable 을 .asMaybe() 로 변형 가능합니다

8. Hot Observable vs Cold Observable

언제 이벤트들이 방출되는지에 따라 Observable을 두가지로 분류할 수 있습니다.

Hot Observable

  • 생성과 동시에 이벤트를 방출하기 시작하는 Observable.
  • Subscribe 되는 시점과 상관없이 Observer 에게 이벤트를 중간부터 전송합니다.

Cold Observable

  • Subscribe 되는 시점부터 이벤트를 생성해 방출합니다.

9. Subscription 공유

Cold Observable 은 subscribe 되는 시점부터 이벤트를 생성해 방출합니다.

여러번의 subcribe 가 있을 대마다 스트림이 중복으로 발생하게 됩니다.

Subject

우리는 실시간으로 Observable에 값을 추가하고 Subscriber에게 방출하는 것이 필요하다. 이 때 Observable이자 Observer인 Subject 를 사용합니다.

Subject를 사용하면 Cold Observable을 Hot Observable로 변환할 수 있습니다.

PublishSubject

PubishSubject는 subscribe된 이후부터 이벤트를 방출합니다. 이 활동은 subscribe을 멈추거나, .completed, .error 이벤트를 통해 Subject가 종료될 때까지 지속됩니다.

  • 종료되었을 때 존재하는 구독자 뿐만 아니라 이후에 구독한 subscriber에게도 종료 이벤트를 보내줍니다.
  • 사용 : 시간에 민감한 데이터를 모델링 할 때 사용합니다 (subscribe 되기 이전의 값이 필요 없는 경우)

BehaviorSubject

PublishSubject 와 비슷하지만 초기 이벤트를 가진 Subject 입니다. subscribe 될때 가장 최신의 .next 이벤트를 전달합니다.

  • BehaviorSubject는 항상 최신의 .next 이벤트를 방출하기 때문에 초기값 없이는 만들 수 없습니다. 초기값이 없다면 PublishSubject를 사용합시다.
  • 사용 : 항상 최신 데이터로 채워놓아야 하는 경우에 사용 (유저 프로필)

ReplaySubject

ReplaySubject는 bufferSize 개의 이벤트를 저장해 subscribe 될 때 저장된 이벤트를 모두 방출합니다

  • 사용 : 최신의 여러 값들을 보여주고 싶을 때 사용 (최근 검색어)

Relay

  • Subject와 다르게 error 나 complete 를 통해서 완전종료될 수 없습니다
  • subscribe 하고 싶을 때는 asObservable을 사용합니다.

PublishRelay

  • PublishSubject를 wrapping 해서 가지고 있습니다.
  • Subject 는 .completed .error 를 받으면 subscribe 이 종료됩니다. 하지만 PublishRelay는 dispose되기 전까지 계속 작동하기 때문에 UI Event에서 사용하기 적절합니다.

BehaviorRelay

  • BehaviorSubject를 wrapping 해서 가지고 있습니다.
  • .value를 사용해 현재의 값을 꺼낼 수 있습니다.
  • Variable이 deprecate 되면서 BehaviorRelay를 대신 사용합니다. .value 의 경우 get-only-property 이므로 유의합시다.
  • value를 변경하기 위해서 .accept()를 사용합니다

--

--