iOS/RxSwift

RxSwift) Subject (3/3) - PublishSubject / BehaviorSubject / ReplaySubject / AsyncSubject

소들이 2023. 10. 12. 20:56

 

 

 

안녕하세요! 소들입니당 :D

드디어.. Subject의 마지막 포스팅이네요

Subject 종류에는 어떤 게 있는지, 실제로 어떻게 사용하는지에 대해

알아볼 건데여!!!

 

이전 Subject의 개념 포스팅들이 너무 어려웠져....?ㅠㅠㅠㅠ

아마 이 포스팅 이해한 사람은.. 많이.. 없을거야.. 후엥ㅠㅠㅠ

이번 포스팅은 개념이 아니라 사용법이니 조금 마음 편하게 공부하시길 바랍니다 ㅎㅎ

모든 포스팅은 편의 말투로 합니다~!

 

 

 

 

1. Subject의 종류 4가지

 

복습을 짧게 하고 가자면,

Subject라는 것은 Observer이자 Observable의 역할을 하는 친구고

Observer가 구독할 경우 모든 이벤트를 다 방출 받는 Cold Obsevable과 달리,

구독을 하는 시점 이후부터 발행되는 이벤트만 받는 Hot Observable로 동작한다 했음

또한 자신을 구독하고 있는 여러 Observer들에게

이벤트가 발행됐을 때 그 값을 전달하는 Observer 역할도 한다고 공부해씀

때문에 당연히 Multicast로 동작하구요?

 

아이 쉽다 쉬워!

근데 지금껏 우리가 Subject를 공부할 때 종류를 공부하지 않았기 때문에

대충 이런 Subject가 있다!!! 하면서 했었단 말임?

 

 

 

 

그게 바로 PublishSubject라는 것이었음

근데 사실.. PublishSubject가 뭐하는 놈인지는 1도 모르고요 ㅎㅎ;;

그냥 Subject는 다 요놈으로 때려 바긍면 되나요? 싶겠지만,

Subject의 종류는 총 4가지나 된답니다.

 

 

 PublishSubject

BehaviorSubject

ReplaySubject

AsyncSubject

 

 

아 뭔 종류가 4가지나 돼 ...!!!!!!  하겠지만..

Subject를 제대로 이해 했다면... 정말정말 쉬움...!!!

하나씩 보겠음다!

 

 

 

1-1. PublishSubject

 

PublishSubject는 구독 이후에 방출된 항목들만 옵저버에게 전달합니다

 

우리가 앞서 Subject를 공부할 때 배운 내용 그대로임..!

Cold Observable과 달리 Hot Observable은

구독 이후에 방출된 항목만 옵저버에게 전달된다고 했음!

따라서 예로 보자면,

 

 

let subject = PublishSubject<String>()

 

 

이렇게 String의 항목을 방출하는 PublishSubject를 생성하고,

 

 

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")

 

 

이 PublishSubject를 구독할 경우,

 

 

 

 

"구독한 이후부터 방출되는 이벤트를 Observer가 받을 수 있다"

를 이해해짜늠

따라서 위와 같은 결과가 나온 걸 알 수 있었움

 

 

아항.. ㅇㅋㅇㅋ!!!! 알앗서!

근데 .. 그럼 다른 녀석들은 구독 전 녀석들도 받는 건가?

그럼 Cold Observable 아녀?? 하고 생각이 들 지 않나여???

의문을 갖고 다음으로 넘어가봅시당

 

 

 

1-2. BehaviorSubject

 

BehaviorSubject는 구독할 경우,

Observable이 가장 최근에 발행한 항목(아무것도 발행하지 않았다면 초기값)을 한번 방출하며

그 이후부터 Observable에 의해 방출된 항목들을 Observer에게 전달합니다

 

정의로 보니 말이 쪼꼼 어려울 수 있는데,

말 그대로 가장 최근에 방출된 값을 얘는 가지고 있음!!!!

그래서 어떤 Observer가 자신을 구독했다고 하면,

그 Observer가 구독하기 이전에 가장 최근 값을 이 Observer에게 방출해주는데,

만약 Observer가 구독하기 전에 이벤트가 한번도 방출이 안 됐으면 어케요!? 하잖음??

 

따라서 한번도 방출이 안 됐을 때를 대비해 전달 할 "초기값"이라는 것을

BehaviorSubject를 선언할 때 같이 정의를 해주어야 함

 

 

let subject = BehaviorSubject<Int>(value: 1)

 

 

이런 식으로!!

value 파라미터를 통해 초기값을 지정 해주고 나면,

이제 이벤트가 방출이 한 번도 안 된 따끈따근한 이 subject를 구독할 경우,

 

 

subject.subscribe(onNext: {
    print("첫번째 Observer가 받는 항목 : \($0)")
}).disposed(by: disposeBag)

 

 

 

 

이때는 아직 방출된 이벤트가 없기 때문에,

우리가 BehaviorSubject를 초기화 할 때 지정한 초기값이 바로 방출됨

근데 이제 이 Subject에 만약 onNext를 통해 여러 이벤트가 방출되고 나면 어케 대냐

 

 

subject.subscribe(onNext: {
    print("첫번째 Observer가 받는 항목 : \($0)")
}).disposed(by: disposeBag)
 
subject.onNext(2)
subject.onNext(3)
 
subject.subscribe(onNext: {
    print("두번째 Observer가 받는 항목 : \($0)")
}).disposed(by: disposeBag)

 

 

이렇게 onNext를 통해 2와 3이라는 값을 방출하고 난 후,

두번 째 Observer가 이 subject를 구독할 시 받게 되는 항목은

가장 최근에 방출된 이벤트인 "3"이 되는 것임

 

 

 

 

어렵지 않죠!?!?!

 

자, 여기서 절대 헷갈리면 안 되는 것이,

구독했을 때 가장 최신에 방출된 값을 "한번" 방출해주는 것이 BehaviorSubject이지

한번 방출 받은 이후부턴 그냥 우리가 알던 Observable처럼 방출되는 값을 계속 받게 되는 것

 

 

아항 정리해보자면,

❄️Cold Observable❄️

구독 시점과 상관 없이

방출하는 모~~든 값을 다 Observer에게 온전히 전달하는 게 목적이라면,

 

🔥Hot Observable(Subject)🔥

구독 시점에 따라 방출 받을 수 있는 값이 달라질 수 있구나!

➡️ 근데 내가 구독 전에 이미 방출되어 날라가버린 이벤트들?  응 필요없어~

싶으면 PublishSubject를 쓰면 되고,

➡️ 에헤이 조졌네 제가 구독하기 전 가장 최근에 방출된 값이라도 "한번"만 받게 해주쇼잉...

할 때 쓸 수 있는 게 BehaviorSubject구나!

 

별거 없져?

근데 만약 나는 아 ... 가장 최근에 방출된 값 한번으로는 부족한데 ...

거.. 서비스 차원에서.. 가장 최근에  방출된 값 4-5개 정도 주면 안 될까..?

 

할 때 쓸 수 있는 게 바로

 

 

 

1-3. ReplaySubject

 

최신 이벤트를 버퍼 사이즈에 맞게 저장하고,

Observer가 구독할 시 버퍼에 있는 이벤트를 모두 전달합니다

BehaviorSubject의 역할에서 "두 개 이상"의 이벤트를 저장하고 싶을 때 사용합니다

 

BehaviorSubject가 가장 최근에 방출된 값을 딱 1번 방출해줬다면

얘는 말그대로 내가 받고싶은 만큼 버퍼의 사이즈를 지정해서 구독 시 받을 수 있음ㅎㅎ

따라서 선언할 때

 

 

let subject = ReplaySubject<Int>.create(bufferSize: 3)

 

 

요롷게 create 메서드를 이용해 버퍼 사이즈를 지정해주면 되는데,

BehaviorSubject와 달리 초기값을 설정해주지 않기 때문에,

 

 

subject.subscribe(onNext: {
    print("첫번째 Observer가 받는 항목 : \($0)")
}).disposed(by: disposeBag)

 

 

아무 항목도 방출하지 않았을 때는

해당 Subject를 구독해도 아무런 값도 방출하지 않음!!!!

 

만약, 다음과 같이 1,2,3,4라는 항목이 순서대로 방출되었을 경우

 

 

subject.subscribe(onNext: {
    print("첫번째 Observer가 받는 항목 : \($0)")
}).disposed(by: disposeBag)
 
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)
 
subject.subscribe(onNext: {
    print("두번째 Observer가 받는 항목 : \($0)")
}).disposed(by: disposeBag)

 

 

이때는 버퍼의 size가 3이기 때문에

가장 최근에 방출된 값 3개만 저장을 할 수 있어서,

이 이후에 두 번째 Observer가 구독을 할 경우,

 

 

이렇게 가장 최근에 발행된 2,3,4라는 항목을 고대로 받을 수 있음!!!

 

다만, 버퍼의 크기를 우리가 지정해주는 만큼

버퍼의 크기는 딱 필요한 만큼만 지정해주는 것이 메모리 관리상 중요함!!

 

 

 

1-4. AsyncSubject

 

AsyncSubject는 completed 이벤트가 전달되기 전까지 어떠한 이벤트도 방출하지 않습니다

completed 이벤트가 전달되면, 가장 최근에 전달된 값을 방출합니다

 

지금까지 위에서 본 3가지의 Subject는

Observer가 Subject을 구독하는 즉시 바로 이벤트를 전달 받을 수 있었음!!

 

하지만 AsyncSubject는 이름에서도 느낌 오듯이

completed 이벤트가 전달되기 전까진 어떠한 이벤트도 방출을 하지 않다가,

completed이란 이벤트가 전달되면, 가장 최근에 전달된 값을 방출 함!!!

 

충분히 이해가 될 거 같으나 예제로 보면,

 

 

let subject = AsyncSubject<Int>()

 

 

이렇게 AsyncSubject를 생성하고

 

 

subject.subscribe(onNext: {
    print("첫번째 Observer가 받는 항목 : \($0)")
}).disposed(by: disposeBag)
 
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)

 

 

구독해서 아무리 값을 전달해도 아무런 Observer는 이를 받을 수 업..서... 🥺

DJDOC의 부치지 못한 편지 ... 노래 죠은뎅..

뭐 여튼 다음과 같이 해당 subject에 대고 onCompleted을 호출하면

 

 

subject.onCompleted()

 

 

요러케 호출 해야만,

 

 

 

 

이제서야 가장 마지막에 전달된 값을 Observer에게 방출하고 정상종료 되는 것임!!!

(물론 초기값이 없ㄱ ㅣ때문에 Observable이 값을 전달하지 않으면 아무것도 방출도지ㅣ 않고 끝남)

 

Subject 사용법 개쉽네 하하 ㅋ

 

 

 

 

2. 정리

 

  PublishSubject BehaviorSubject ReplaySubject AsyncSubject
구독 시 방출되는 최근 값 X 가장 최근 값
(없을 시 초기값)
버퍼 크기만큼의 최근 값들
(없을 시 X)
X
특징 구독 이후로 방출되는 이벤트만 받음 가장 최근 값 1번 받을 수 있음 가장 최근 값을 여러 번 받고 싶을 때 사용 onCompleted이 불릴 때 가장 최근 값 한번 받음

 

 

 

 

 

 

 

 

 

 

 

 

 

,

,

,

훔 ....... 이전 포스팅들에 비해 매우 쉽군요 ..

근데.. 재밌는 게 뭔지 아세요 ....

저는 사이코 개발자인 걸까요.. 아니면 사이코 글쟁이인 걸까요..

어려운 개념 포스팅이 훨씬 재밌고,,, 이런 사용성 포스팅이 너무 재미가 엄습니다 .. 후 

 

 

진짜 BJ 이상호 아님

 

 

오늘의 마무리는 아푸리카의 아무말 대잔치

틀린 내용이나 오타는 언제든 지적 환영입니다 :>