Search
Duplicate

RxSwift - Subject의 Observable 역할

Created
2023/09/17 04:33
Tags
RxSwift

RxSwift - Subject의 Observable 역할

 Subject 란?

SubjectObserver이자 Observable 이다. Observer 이기 때문에 하나 이상의 Observable을 구독할 수 있으며, 동시에 Obervable이기 때문에 새로운 항목(item)들을 방출하거나 재방출 한다.

Observable 이란?

비동기 이벤트를 관찰이 가능한 형태로 만든 것으로, 해당 이벤트가 발생 했을 때 “항목(item)” 이란 것을 “방출(emit)” 한다.

Observer 란?

내가 원하는 비동기 이벤트를 방출하는 Observable이 있을 경우, 해당 Observable을 “구독(Subscribe)” 하여 항목이 방출 되었을 때 그 항목을 받아 처리할 수 있다.
Observable을 어떻게 구현하냐면
public class Observable<Element>: ObservableType {
Swift
복사
ObservableType 이란 프로토콜을 채택하는 제네릭 클래스로 구현이 되어있다. 따라서 Observable을 만들기 위해선 이 Observable이란 클래스를 사용해야 했다.
이때까지는 Observer를 직접 생성하거나 살펴보진 않았는데, 그 이유는 ObservableType에서 제공하는 구독 메서드, 즉 subscribe를 사용하면
let observer = AnonymousObserver<Element> {...} return Disposables.create ( self.asObservable().subscribe(observer), disposable )
Swift
복사
자체적으로 AnonymousObserver란 Observer를 생성해서, 해당 Observable에 subscribe를 해줬기 때문이다.
하지만 AnonymousObserver 라는 것도 자세히 보면
final class AnonymousObserver<Element>: ObserverBase<Element> {
Swift
복사
ObserverBase란 클래스를 상속받고 있는 것을 볼 수 있고,
class ObserverBase<Element>: Disposable, ObserverType
Swift
복사
이 ObserverBase란 클래스는 ObserverType 이란 프로토콜을 채택하고 있는 것을 볼 수 있다. 이것은 Observer 역할을 하기 위해선
public protocol ObserverType { func on(_ event: Event<Element>)
Swift
복사
ObserverType 이라는 프로토콜을 준수해야한다.

 요약

Observable의 역할을 하기 위해선 Observable 이란 제네릭 클래스를 상속 받아야 하고,
Observer의 역할을 하기 위해서는 OserverType 이란 프로토콜 채택이 필요하다.
하지만 Subject는 Observable과 Observable의 역할을 동시에 한다고 했다.
그러면 Subject는 Observable 클래스를 상속받는 동시에, ObserverType도 채택하고 있어야 한다.
그래서 Subject는 Observer 이자 Observable의 역할을 한다’ 는 것만 이해!

 Subject는 언제, 왜 쓸까?

그러면 Subject는 언제, 왜 쓰는 것일까?
이를 이해하기 위해서는 Observable과 Subject의 차이를 보면서 이해하자!

 Hot Observable VS Cold Observable

Cold Observable
구독이 되어야만 비로소 항목(이벤트)을 방출하는 Observable
어느 시점에 구독하든 같은 결과를 받는다.
Hot Observable
구독 여부와 상관없이 항목(이벤트)을 방출하는 Observable
구독하는 시점에 따라 방출되는 결과가 다르다.
처음부터 방출되는 결과를 받지 못할 수도 있다.
Observable의 특징은
let observable = Observable.just(1)
Swift
복사
이렇게 Observable을 생성한다해서 바로 항목인 “1”을 방출하지 않는다는 것
그러면 언제 방출할까?
observable.subscribe(onNext: { (data) in print(data) // 1 })
Swift
복사
이렇게 이 Observable에 대고 “구독”을 했을 때, 그때야 1이란 항목이 방출 되었었다.
 우리가 지금껏 공부했던 Observable 연산자들은 모두 Observer가 Observable을 구독 되어야만 비로소 해당 이벤트가 방출되는 Cold Observable 이었단 것이다.
하지만 Subject는 Hot Observable 이다!
따라서 Subject를 사용할 경우, 내가 구독한 시점부터 방출되는 이벤트만 받을 수 있고, 내가 구독하기 전에 이미 방출되어버린 이벤트는 받을 수가 없다.
예시 1) 유튜브에서 “알림” 이라는 것을 Observable을 구현해본다면?
우리가 만약 유튜버를 알림 설정을 하고 싶다면, 이제 알림 설정을 한 시점부터, 그 유튜버가 영상을 올릴 때 알림이 와야 한다.
그럼 이때는 Observable을 구독한 시점부터 항목이 방출되는 Hot Observabl을 사용해야 한다.
만약 이때, Cold Observable을 사용한다면, 그 유튜버가 가입 시기부터 쓴 글과 라이브들의 과거 알림들도 다 오게되는 참사가 일어난다!
예시 2)
let observable = Observable.just(1) let observable = Observable<String>.create { observer in observer.onNext("첫 번째 방출") observer.onNext("두 번째 방출") observer.onCompleted() observer.onNext("세 번째 방출") return Disposables.create() }
Swift
복사
just의 경우, 1이란 숫자를 한번 방출!
create의 경우, print를 두 번 찍고, completed를 호출해서 정상 종료!
→ 그리고, 실제 이 Observable을 구독했을 때, 이렇게 미리 정의된 코드에 의한 항목이 방출되며, Observer는 이 방출되는 항목을 오롯이 다 받을 수 있었다.
이것이 바로 Cold Observable 이다!
let subject = PublishSubject<String>()
Swift
복사
Hot Observable인 Subject는 이렇게 선언한다.
Cold Observable과 다른 점은 어떤 항목을 방출한 것인지에 대한 정의가 없다는 것이다.
이 뜻은, Hot Observable은 어떤 항목을 방출한 것인지를 생성 당시 정의해두는 것이 아니라, 내가 원하는 시점마다 항목을 방출할 수 있다는 것이다.
let subject = PublishSubject<String>() subject.onNext("1") subject.onNext("2")
Swift
복사
구독 했을 때, 온전히 처음부터 모든 항목을 다 방출해줘야 하는 Cold Observable과 달리, 원할 때마다 onNext라는 것을 통해 항목을 발행할 수 있다.
subject.subscribe(onNext: { print("첫 번째 Observer가 받는 항목: \($0)") }).disposed(by: disposeBag) subject.onNext("1") subject.onNext("2") subject.subscribe(onNext: { print("두 번째 Observer가 받는 항목: \($0)") }).disposed(by: disposeBag) subject.onNext("3") // 첫 번째 Observer가 받는 항목 : 1 // 첫 번째 Observer가 받는 항목 : 2 // 첫 번째 Observer가 받는 항목 : 3 // 두 번째 Observer가 받는 항목 : 3
Swift
복사
이렇게 Observer가 받을 수 있는 항목이 달라질 수 있게 되는 것이다.

 Observable(unicast) VS Subject(multicast)

Cold Observable : Observer가 어느 시점에 구독하든 똑같은 항목을 발행 → unicast
Hot Observable : Observer가 언제 구독하든 말든 발행 → multicast

 Observable (unicast)

Observable은 나를 구독한 Observer가 몇 개든 간에, “독자적인 실행”을 가진다.
let observable = Observable<Int>.deferred { return Observable.just(Int.random(in: 0..<100)) }
Swift
복사
이렇게 defer를 통해 Observable을 생성했다. defer는 Observable이 구독될 당시에 항목을 생성한다.
그리고 이제 이 Observable을 여러 Observer에서 구독하면
observable.subscribe(onNext: { print("첫 번째 Observer가 받는 항목: \($0)") }).disposed(by: disposeBag) observable.subscribe(onNext: { print("두 번째 Observer가 받는 항목: \($0)") }).disposed(by: disposeBag) // 첫 번째 Observer가 받는 항목 : 3 // 두 번째 Observer가 받는 항목 : 90
Swift
복사
이렇게 두 Observer가 받는 값이 서로 다른 것을 볼 수 있다.
이것이 Observable이 자신을 구독하는 Observer””에 대해 “독자적인 실행”을 갖는다는 것이다.
이 Observable에 대한 Observer가 몇 개건 간에, 해당 Observer가 구독을 시작했을 경우, 그 구독에 대한 Observable이 각각 실행되어 Observer들이 서로 다른 값을 갖게 된다.
그렇기 때문에, Cold Observable은 unicast 라는 것이다.

 Subject (multicast)

Subject가 multicast 라는 말은, Subject는 “하나의 Observable의 실행”이 여러 Subscribe에게 “공유”된다 는 말이다.
subject.subscribe(onNext: { print("첫 번째 Observer가 받는 항목 : \($0)") }).disposed(by: disposeBag) subject.subscribe(onNext: { print("두 번째 Observer가 받는 항목 : \($0)") }).disposed(by: disposeBag) subject.onNext(Int.random(in: 0..<100)) // 첫 번째 Observer가 받는 항목 : 47 // 두 번째 Observer가 받는 항목 : 47
Swift
복사
이렇게 subject에 항목이 발행될 경우, 이렇게 해당 Subject를 구독한 Observer들은 모두 “동일한” 결과를 받게된다.
때문에 Subject는 multicast라는 것이다.

 Reference