Subject
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(읽기전용)