RxSiwft - Subject 알아보기

Tabber·2021년 9월 2일
1

Reactive Extension

목록 보기
3/4
post-thumbnail

이 글은 naljin님의 글을 보고 정리하는 식으로 쓰는 글입니다.

Subject

subject는 Observer 나 Observable 처럼 행동하는 Rx의 일부 구현체에서 사용 가능한 연결다리 혹은 프록시 이다.
그렇기 때문에, Observable이나 Subject 모두 Subscribe 할 수 있다.

다만 subscribe의 차이가 있다면 Subject는 multicast 방식이기 때문에 여러개의 Observer를 subscribe 할 수 있다.
단순 observable 은 unicast방식이기 때문에, Observer 하나만을 Subscribe 할 수 있다.

음.. 무슨말인지 이해가 가는가?
난 안 간다. 그냥 쉽게 말해보자.
Observable 은 유니캐스트(1:1 연결방식) 이므로 Observer 하나만을 Subscribe 할수 있다라는 거다.
근데 Subject 는 멀티 캐스트(1:N 연결방식) 이므로 여러개의 ObserverSubscribe 할 수 있다라는 점이다.

아까 위에서 설명한 정의를 보면 연결다리 혹은 프록시 라고 했다.
이 사진을 보면 약간 어떤 느낌인지 이해가 살짝 가려고 하긴 한다.. 여러개를 연결할 수 있는 다리? 같은 역할을 해주긴 하는 것 같다.

일단 UnicastMulticast의 차이를 알아보자.

Unicast vs Multicast

우선 Observable의 Unicast
Unicast란 각각 Subscribed 된 Observable에 대해 독립적인 실행을 갖는 것..이라고는 하는데 무슨말인지 모르겠다.
코드를 한번 봐보자.

let randomNumGenerator1 = Observable<Int>.create { observer in
    observer.onNext(Int.random(in: 0..<100))
    return Disposables.create()
}

randomNumGenerator1.subscribe(onNext: { (element) in 
    print("observer 1: \(element)")
})

randomNumGenerator1.subscribe(onNext: { (element) in 
    print("observer 2: \(element)")
})

// --- print ---

observer 1 : 54
observer 2 : 46

// 출처 : https://sujinnaljin.medium.com/rxswift-subject-99b401e5d2e5

다른 숫자가 출력이 된다.
Observer 가 해당 Observable에 대해 독자적인 실행을 갖기 때문에, 동일한 Observable 구독을 통해 생성된 두개의 Observer라고 해도 Observable이 각각 실행되면서 Observer에게 서로 다른 값이 가는것이다.

이제 Subject의 multicast를 보자.
multicast가 된다는건 하나의 Observable실행이 여러 Subscriber에게 공유되는 것을 뜻하게 된다.

    let randomNumGenerator2 = BehaviorSubject(value: 0)
    randomNumGenerator2.onNext(Int.random(in: 0..<100))
    
    randomNumGenerator2.subscribe(onNext: { (element) in
        print("observer subject 1 : \(element)")
    })
    randomNumGenerator2.subscribe(onNext: { (element) in
        print("observer subject 2 : \(element)")
    })

    --------------------print------------------

observer subject 1 : 92
observer subject 2 : 92

// 출처 : https://sujinnaljin.medium.com/rxswift-subject-99b401e5d2e5

구독해서 생성된 Observer에게 Observable의 동일한 실행이 간다.
Observable의 실행이 공유되면서 같은 값이 출력이 된다.

다시 정리해보자면, Observable에서 Subscribe를 하면 이벤트로 전달되는 것은 항상 다른것이고,
Subject에서 Subscribe를 하면 이벤트로 전달되는 것은 Subscribe 전에 수행 된 onNext 등의 하나의 공통된 것이다.

Subject 의 종류

Subject 의 종류에는 4가지가 존재한다.

ReplaySubject

버퍼 사이즈에 따라 받을 수 있는 갯수가 다르다.
Observable 의 completed 이나 Error 에 상관이 없다.

처음에는 디폴트값이 없어서 아무것도 내보내질 않는다. 하지만 Observable이 발생했을 경우에 내보내길 시작한다.
그리고, 다른 시점에 새로운 Subscribe가 생성됐다면, 그 전에 생성된 모든 Observable을 다 내보낸다.

그러니까 언제 구독을 하든지간에 현재 Observable에 있는 만들어 졌던 데이터를 때려박는 것 같다. (확실하지 않다)

PublishSubject


디폴트 값이 없다. 따라서 일단 뭐 아무것도 주질 않는다. 하지만
PublishSubject 는 구독한 시점부터 반환가능한 Observable가 있을경우 Observer에게 반환해주는 역할을 한다.

그러니까 언제 구독을 했느냐의 따라서 받을 수 있는 데이터(Observable) 의 수가 달라진 다라는 것 같다.

에러 발생 시

에러 발생시에는 Observable을 내보내지 않고, 에러를 내보내게 된다.

BehaviorSubject


BehaviorSubject 는 Observer가 구독할 때 내보낸 가장 최근의 것을 시작으로 나머지 Observable들을 내보낸다.
이때, 아무것도 내보내지 않은 경우 기본값을 내보낸다.

에러 발생 시

에러 발생 시 다른 Observer로 구독을 해도 가장 최근의 반환은 에러 였으니 에러를 내보낸다.

AsyncSubject

어디서 Subscribe를 하든지간에, 작업이 Completed 되기 전까지는 데이터를 주지 않는다.
그러다, Completed가 뜰 때, 연결되어 있던 Subscribe 들에게 데이터를 준다.

정리

Subject는 여러개의 Observable을 관리할 수 있는 통로 역할을 하는 것을 알아보았고,
Subject를 관리하는 종류는 총 4가지로 ReplaySubject, PublishSubject, BehaviorSubject, AsyncSubject 을 알아보았다.

profile
iOS 정복중인 Tabber 입니다.

0개의 댓글