IOS/RXSwift

Subject

william 2021. 9. 19. 14:54
반응형

PublishSubject

 

 

publishSubject를 만들어 보겠습니다.

 

----------------------------------------------------------

let disposeBag = DisposeBag()

let subject = PublishSubject<String>()

 

 

"subject가 시작되는 시점에 내부에 아무런 이벤트가 없는 상태입니다.(생성자 없음)

따라서 생성 직후 옵저버가 구독할 경우

아무런 이벤트가 전달 되지 않습니다. 즉 PublishSubject는 구독 이후 이벤트가 전달됩니다."

 

subject.onNext("Hello")    =>전달 x

 

let o1 = subject.subscribe{

    print(">>1",$0)

}

o1.disposed(by: disposeBag)

----------------------------------------------------------

subject.onNext("RxSwift")      >> 1 next(RxSwift)   

구독후 이벤트 전달 하면 바로 값이 나옵니다.

 

추가적으로  새로운구독자를  추가해보겠습니다.

----------------------------------------------------------

 

let o2 = subject.subscribe{

    print(">>2" , $0)

}

o2.disposed(by: disposeBag)

 

----------------------------------------------------------

subject.onNext("Subject")

>> 1 next(Subject)

>> 2 next(Subject)

 

두번째 구독자의(o2옵저버) 구독 시점을 보게 되면 앞에 받았던 두개의 next이벤트는 받지 않습니다.

 

 

"두개의 next이벤트"

subject.onNext("Hello")

subject.onNext("RxSwift")

즉 마지막 subject.onNext("Subject")이벤트만 받게 되고

이 이벤트를 현재 구독하고있는 두개의 구독자(모든 구독자)에게 전달하게 되는것입니다!

 

마지막으로 Complete이벤트를 호출해보겠습니다.

 

subject.onCompleted()

>> 1 completed

>> 2 completed

 

그럼 Complete이벤트를 호출 후 구독을 해보면 어떻게 될까요?

 

let o3 = subject.subscribe{ print(">>3", $0)}

o3.disposed(by: disposeBag)

>> 3 completed

 

옵저버블과 마찬가지로 completed이벤트가 전달된후에는 새로운 구독자에게 전달할 next이벤트가 없기때문에 바로

complete이벤트가 전달됩니다.

 

BehaviorSubject

publishSubject와 크게 다르지 않지만 초깃값을 저장한다는것에서 차이가 있습니다.

따라서 마지막에 전달된 이벤트를 받고싶을때 사용합니다.

 

let p = PublishSubject<Int>()

 p.subscribe { print("PublishSubject >> ", $0) }

    .disposed(by: disposeBag)

 

let b = BehaviorSubject<Int>(value: 0)

 b.subscribe{ print("BehaviorSubject >>", $0)}

     .disposed(by : disposeBag)

 

BehaviorSubject >> next(0)  

=> 생성될때 만들어진 값을 바로 전달 즉 BehaviorSubject를 생성하면 내부에 next이벤트가 만들어집니다.

즉 가장 최근 이벤트를 가지고있다가 구독자가 생기면 저장되어있던 next이벤트가 바로 전달됩니다.

 

또한 next이벤트를 추가적으로 해주면 이벤트가 전달됩니다.

BehaviorSubject >> next(1)  값이 바뀜  

 

이번에는 새로운 옵저버를 추가해보겠습니다.

 b.subscribe{ print("BehaviorSubject2 >>", $0)}

     .disposed(by : disposeBag)

 

BehaviorSubject2 >> next(1)  

 

=>값을 저장하고있다가 전달합니다.

 

 

 

ReplaySubject

지정된 buffer size만큼 저장합니다.

단 buffer는 메모리를 사용하기 때문에 메모리 사용량에 신경써야합니다.

 

앞에서 생성자로 생성한것과는 다르게 create메소드로 생성합니다.

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

 

(1...10).forEach { rs.onNext($0)}

rs.subscribe { print("Observer 1 >>" , $0) }

   .disposed(by : disposeBag)

 

Observer 1 >> next(8)

Observer 1 >> next(9)

Observer 1 >> next(10)

 

 

rs.subscribe { print("Observer 2>>" , $0) }

   .disposed(by : disposeBag)

 

Observer 2 >> next(8)

Observer 2 >> next(9)

Observer 2 >> next(10)

 

rs.onNext(11)  => 즉 시 전달 + buffer에서 가장 오래된 이벤트를 삭제됩니다.

Observer 1 >> next(11)

Observer 2 >> next(11)

 

rs.subscribe { print("Observer 3>>" , $0) }

   .disposed(by : disposeBag)

 

Observer 3 >> next(9)

Observer 3 >> next(10)

Observer 3 >> next(11)

 

rs.onCompleted()  => 모든 구독자에게 이벤트가 전달됩니다.Observer 1 >> completedObserver 2 >> completedObserver 3 >> completed

 

 

이 상태에서 새로운 구독자를 추가한다면 버퍼에 저장된 이벤트 전달 후 completed이벤트가 전달됩니다(error도 마찬가지),즉 종료여부에 관계없이 항상 버퍼에 저장된 이벤트를 새로운 구독자에게 전달합니다

 

rs.subscribe { print("Observer 4>>" , $0) }

   .disposed(by : disposeBag)

 

Observer 4 >> next(9)

Observer 4 >> next(10)

Observer 4 >> next(11)

Observer 4 >> completed

 

AsyncSubject

=> completed이벤트가 전달된 이후 가장 최근의 이벤트를 구독자에게 전달 합니다.

만약이때 이벤트가 없다면 그냥 completed이벤트만 호출 됩니다.

 

let subject = AsyncSubject<Int>()

subject

     .subscribe { print($0) }

     .disposed(by: bag)

 

subject.onNext(1)

subject.onNext(2)    //이때까지 아무런 이벤트가 전달되지않습니다.

subject.onNext(3)

 

sunject.onCompleted()

completed이벤트 전달후 

next(3)

completed

 

 

Relay

 

let prelay = PublishRelay<Int>()

prelay.subscribe {print("1: \($0)") }

      .disposed(by: bag)

 

prelay.accept(1)  

// 1: next(1)

------------------------------------------------

let brelay = BehaviorRelay(value:1)

brelay.accept(2)           =>accept 메서드를 통해 새로운 값을 설정할수있다

brelay.subscribe {print("2: \($0)") }

      .disposed(by: bag)

 

//2: next(2)

 

brelay.accept(3)   => 즉시 2:next(3)

 

print(brelay.value) // 3(읽기전용)

 

 

 

 

 

 

반응형