RxSwift) Subject (3/3) - PublishSubject / BehaviorSubject / ReplaySubject / AsyncSubject
안녕하세요! 소들입니당 :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이 불릴 때 가장 최근 값 한번 받음 |
,
,
,
훔 ....... 이전 포스팅들에 비해 매우 쉽군요 ..
근데.. 재밌는 게 뭔지 아세요 ....
저는 사이코 개발자인 걸까요.. 아니면 사이코 글쟁이인 걸까요..
어려운 개념 포스팅이 훨씬 재밌고,,, 이런 사용성 포스팅이 너무 재미가 엄습니다 .. 후
오늘의 마무리는 아푸리카의 아무말 대잔치
틀린 내용이나 오타는 언제든 지적 환영입니다 :>