iOS Ellen

[RxSwift] PublishSubject & BehaviorSubject 이해하기 본문

iOS/RxSwift

[RxSwift] PublishSubject & BehaviorSubject 이해하기

Ellen61 2022. 6. 18. 02:34

https://reactivex.io/documentation/subject.html

 

ReactiveX - Subject

If you have a Subject and you want to pass it along to some other agent without exposing its Subscriber interface, you can mask it by calling its asObservable method, which will return the Subject as a pure Observable. See Also

reactivex.io

 

오늘은 RxSwift에서 PublishSubject & BehaviorSubject 에 대해서 알아볼까 합니다!

 

A Subject is a sort of bridge or proxy that is available in some implementations of ReactiveX that acts both as an observer and as an Observable. Because it is an observer, it can subscribe to one or more Observables, and because it is an Observable, it can pass through the items it observes by reemitting them, and it can also emit new items.

   

본문 내용을 보면 Subject는 Observable과 Observer의 역할을 한다고 설명되어있네요!

Subject 하나로 새로운 값을 추가하고 Subscriber에게 방출할 수 있겠네요.

오늘은 PublishSubject와 BehaviorSubject에 대해서 알아볼까해요!

 

PublishSubject

 

값이 없는 상태로 시작하며 구독한 이후에 새로 발생한 값을 subscriber에게 방출한다고 합니다.

예시 코드를 작성해 볼까요? 꼭 따라 쳐보는 연습을 해보세요!

import RxSwift
import Foundation

let disposeBag = DisposeBag()

let publishSubject = PublishSubject<String>() // PublishSubject 생성

publishSubject.onNext("1번") // 새로운 값 설정

let subscriber1 = publishSubject // 첫번째 구독자 생성
    .subscribe(onNext: {
        print("1번째 구독:", $0)
    })
    .disposed(by: disposeBag)

publishSubject.onNext("2번") // 새로운 값 설정
publishSubject.onNext("3번") // 새로운 값 설정


let subscriber2 = publishSubject // 두번째 구독자 생성
    .subscribe(onNext: {
        print("2번째 구독:", $0)
    })
    .disposed(by: disposeBag)

publishSubject.onNext("4번") // 새로운 값 설정
publishSubject.onCompleted() // 컴플리트
publishSubject.onNext("5번") // 새로운 값 설정

 

 

 

 

 

 

 

스크롤을 잠시 멈추고 로그가 어떻게 찍힐지 예상해봅시다!!!

 

⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

실행 결과

다시 코드와 함께 분석해봅시다

import RxSwift
import Foundation

let disposeBag = DisposeBag()

let publishSubject = PublishSubject<String>()

publishSubject.onNext("1번") // 구독 이전에 발생한 이벤트이므로 print 되지 않는다.

let subscriber1 = publishSubject
    .subscribe(onNext: {
        print("1번째 구독:", $0)
    })
    .disposed(by: disposeBag)

publishSubject.onNext("2번")
publishSubject.onNext("3번")


let subscriber2 = publishSubject // 마찬가지로 구독 이전에 발생한 1,2,3번 이벤트는 방출되지 않는다.
    .subscribe(onNext: {
        print("2번째 구독:", $0)
    })
    .disposed(by: disposeBag)

publishSubject.onNext("4번") // 구독자 1,2 둘다 방출
publishSubject.onCompleted()
publishSubject.onNext("5번") // 에러나 컴플릿 이후에는 데이터 방출하지 않는다.

 

예시코드를 마블 다이어그램으로 표현해봤어요

파란색 화살표는 구독을 나타내고 검정색 화살표는 방출을 뜻합니다.

마지막에 검정색 세로줄은 컴플리트를 표현했어요.

 

앞서 설명했듯이 PublishSubject는 구독이후에 새로운 값이 발생한 경우에 데이터를 방출합니다.

첫번째 구독자는 1번 값이 생겨난 이후에 구독했기 때문에 1번이라는 스트링이 프린트되지 않았습니다.

하지만 구독 이후에 발생한 2,3,4번 값들은 정상적으로 방출되었습니다.

두번째 구독자는 값이 3번으로 변경된 이후 시점에 구독했기 때문에 4번만 방출하겠죠??

 

하지만 구독 이후에 생겨난 5번 값은 왜 방출되지 않았을까요??

Observable은 completed나 error가 발생한 경우에는 데이터를 방출하지 않습니다. 꼭 유념하세요!!!

 

 

BehaviorSubject

BehaviorSubject는 하나의 초기값을 가진 상태로 시작하고 subscriber에게 초기값 or 최신값을 방출합니다.

즉 구독한 시점에서 가장 최근 발생한 값을 방출합니다! 없다면 초기값을 방출하는거죠!

 

 

 

예시코드를 볼까요?

let behaviorSubject = BehaviorSubject<String>(value: "초기값") // 초기값을 지정해야합니다!

behaviorSubject.onNext("1번")

behaviorSubject.subscribe {
    print("1번째 구독:", $0.element ?? $0)
}
.disposed(by: disposeBag)

behaviorSubject.onNext("2번")

behaviorSubject.subscribe {
    print("2번째 구독:", $0.element ?? $0)
}
.disposed(by: disposeBag)

behaviorSubject.onNext("3번")

 

 

 

스크롤을 잠시 멈추고 로그가 어떻게 찍힐지 예상해봅시다!!!

 

⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

예상했던 대로 로그가 찍혔나요??? 어떠셨나요?

이번엔 코드 분석 없이 바로 마블 다이어그램으로 가봅시다

 

값 변경 이후에 구독해도 가장 최근 값이 방출되는 모습을 볼 수 있습니다.

초기값도 로그에 잘 찍히는지 확인해보고 싶네요! 한번 코드를 수정해볼까요?

 

let behaviorSubject = BehaviorSubject<String>(value: "초기값") // 초기값을 지정해야합니다!

// behaviorSubject.onNext("1번") 주석처리

behaviorSubject.subscribe {
    print("1번째 구독:", $0.element ?? $0)
}
.disposed(by: disposeBag)

behaviorSubject.onNext("2번")

behaviorSubject.subscribe {
    print("2번째 구독:", $0.element ?? $0)
}
.disposed(by: disposeBag)

behaviorSubject.onNext("3번")

 

초기값이 잘 방출되는 것을 볼 수 있습니다.

'iOS > RxSwift' 카테고리의 다른 글

[RxSwift] BehaviorSubject 실험하기!  (0) 2022.07.05