iOS/RxSwift

[RxSwift] Subject

최지철 2023. 10. 29. 18:00
728x90
반응형

Subject

  • Subject를 이해하기위해서는 Observable과 Observer를 먼저 이해야한다.
  • Subject는 Observable인 동시에, Observer이다.
    • Observable는 다른 Observable를 구독 못함, Observer 또한 이벤트를 다른 Observer에 전달 못함
    • 반면, Subject는 다른 Observable로 부터 이벤트를 전달받아, 구독 가능

PublishSubject

  • 빈 상태로 생성되고, 새로운 element가 subscribe 이후의 event만 subscriber에게 전달된다.

BehaviorSubject

  •  PublishSubject와 달리 기본값을 가진 채로 생성되고, 초기값 혹은 최신 element 값을 방출한다.

ReplaySubject

  • 정해진 buffer size를 가진 채로 생성되고, 새로운 구독자에게 방출한다.

AsyncSubject

  • completed 이벤트가 방출될 때만 마지막 next 이벤트를 방출한다. 

 

PublishSubject

  • subject로 전달되는 이벤트를 Observer에게 전달하는 가장 기본적인 subject

PublishSubject

  • 첫번째 줄은 Publish Subject이고, 두세번째 줄은 subscriber에 해당한다. 위로 가는 점선은 subscribe, 아래로 향하는 점선은 emit을 뜻한다. *emit 은 방출을 뜻한다.
  • 첫번째 subscribe는 1번 이후에 구독을 시작했기 때문에 1 이벤트는 받지 못하고, 2와 3 이벤트만 받았다. 두번째 subscribe는 2번 이후에 구독을 시작하여 3 이벤트만 받았다고 보면 된다.
  • Publish Subject는 이벤트를 받는 즉시, 구독자에게 이벤트를 전달한다. 그래서, subject가 최초로 생성되는 시점과 구독이 되는 시점 사이에 발생한 이벤트는 그냥 사라진다. 이것이 Publish Subject의 가장 큰 특징이다.
    • 이벤트가 사라지는 것에 대한 걱정이 있다면, ColdObservable 또는 ReplaySubject를 사용한다.
          let subject = PublishSubject<String>()
            subject.onNext("example")

            // 첫 번째 구독 요청
            let subscriptionOne = subject
                .subscribe(onNext: { (string) in
                    print(string)
                })
            
            subject.on(.next("1"))
            subject.onNext("2")
            // prints : 1, 2

            // 두 번째 구독 요청
            let subscriptionTwo = subject
                .subscribe({ (event) in
                    print("2)", event.element ?? event)
                })

            subject.onNext("3") // print : 2) 3
            
            subscriptionOne.dispose()
            subject.onNext("4") // print : 2) 4
            
            subject.onCompleted() // print : 2) completed
            
            subject.onNext("5") // none of print

            subscriptionTwo.dispose()

            let disposeBag = DisposeBag()

            subject
                .subscribe {
                    print("3)", $0.element ?? $0) // print : 3) completed
            }
                .disposed(by: disposeBag)

            subject.onNext("?") // none of print

BehaviorSubject

  • 하나의 초기값으로 시작, 최신 값(.next)만 새로운 subscriber에게 emit
  • Publish Subject유사하나, subject를 생성하는 방식에 차이가 있다.
    • 생성시에 초기값을 가지고 시작한다.
    • 구독자에게  초기값 또는 최신값을 전달한다.
    • 구독 전에 발생한 최근 요소와 이후에 발생하는 모든것들을 전달 받는다.
      BehaviorSubject

subscribe : 1번째 가로 줄

subscriber : 2,3번째 가로 줄

  • 첫 번째 이벤트가 발생 한 후 첫 번째 subscriber(두 번째 줄)가 구독을 시작했지만, 1을 받음(PublishSubject와의 차이 초기값을받음)
  • 두 번째 이벤트가 발생 한 후 두 번째 subscriber(세 번째 줄)가 구독을 시작했지만, 2을 받음
      // BehaviorSubject는 초기값이 필수 이므로 초기화값을 삽입
        let subject = BehaviorSubject(value: "Initial value")
        let disposeBag = DisposeBag()
        
        subject.onNext("X")

        subject
            .subscribe{
                print("1)", $0)
            }
            .disposed(by: disposeBag)
        // print : 1) next(X)
        
        subject.onError(MyError.anError)
        // print : 1) error(anError)
        
        subject
            .subscribe {
                print("2)", $0)
            }
            .disposed(by: disposeBag)
        // print : 2) error(anError)

ReplaySubject

  • 2개이상 이벤트를 저장했다가, 구독자에게 전달하고 싶다면, ReplaySubject가 제격이다.
  • create를 통해 생성하고, 버퍼의 크기를 정해주어야한다.
  • 버퍼 사이즈만큼 새로운 subscriber에게 emit

ReplaySubject

  • 첫 구독자가 구독시, 최대 2개의 이벤트를 받음(버퍼사이즈가 2일시)
  • 두번째 구독자 구독시도 마찬가지 (버퍼사이즈가2일시)
  • 버퍼 사이즈는 메모리에 할당되므로 버퍼 사이즈가 커질 수록 메모리에 큰 부하를 갖는 것을 주의

AsyncSubject

  • 이벤트를 전달하는 시점에서 차이점이 있다.
  • subject가 completed이벤트가 전달되기전까지, 어떤 이벤트도 구독자에게 전달되지 않는다
  • completed이벤트가 전달되면, 가장 최근에 전달된next이벤트 1개를 구독자에게 전달한다.
let subject = AsyncSubject<Int>()
subject.subscribe(onNext: {
    print("첫번째 Observer가 받는 항목 : \($0)")
}).disposed(by: disposeBag)
 
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)

subject.onCompleted()
728x90
반응형