PublishSubject는 서브젝트로 전달되는 이벤트를 옵저버에게 전달하는 가장 기본적인 형태의 서브젝트.
let disposeBag = DisposeBag()
enum MyError: Error {
case error
}
let subject = PublishSubject<String>()
//타입파라미터를 문자열로 하고있다.
//문자열이 포함된 NextEvent를 받아서 다른 옵저버에게 전달할 수 있다.
//생성자를 호출할때에는 파라미터를 전달하지 않는다.
//이 서브젝트는 비어있는 상태로 생성된다.
//서브젝트가 생성되는 시점에는 내부에 아무런 이벤트가 저장되어있지 않는다.
생성 직후에 옵저버가 구독을 시작하면 아무런 이벤트도 전달되지 않는다.
서브젝트는 옵저버블인 동시에 옵저버다.
다른 소스로부터 이벤트를 전달받을 수 있고 다른 옵저버로 이벤트를 전달할 수 있다.
옵저버블에서 옵저버로 NextEvent를 전달할 때 옵저버에서 OnNext메서드를 호출하고, 파라미터로 요소를 전달했다.
서브젝트 역시 옵저버이기 때문에 onNext메서드를 호출할 수 있다.
let subject = PublishSubject<String>()
subject.onNext("Hello")
//지금은 서브젝트를 구독하고있는 옵저버가 없기 때문에 이 이벤트는 처리되지 않고 그냥 사라진다.
서브젝트는 옵저버블이고 다른 옵저버가 구독할 수 있다.
새로운 옵저버를 추가하고 서브젝트를 구독해본다.
let subject = PublishSubject<String>()
subject.onNext("Hello")
let o1 = subject.subscribe{ print(">> 1", $0) }
o1.disposed(by: disposeBag)
여전히 콘솔에는 아무것도 출력되지 않는다.
PublishSubject는 구독 이후에 전달되는 새로운 이벤트만 구독자에게 전달한다.
그래서 구독자가 구독을 시작하기전에 전달되었던 NextEvent는 o1옵저버로 전달되지 않는다.
let subject = PublishSubject<String>()
subject.onNext("Hello")
let o1 = subject.subscribe{ print(">> 1", $0) }
o1.disposed(by: disposeBag)
subject.onNext("RxSwift")
//>> 1 next(RxSwift)
그러면 RxSwift를 담은 NextEvent가 서브젝트로 전달되고 서브젝트는 이 이벤트를 구독자에게 전달한다.
그래서 결과를 보면 NextEvent가 출력된다.
let subject = PublishSubject<String>()
subject.onNext("Hello")
let o1 = subject.subscribe{ print(">> 1", $0) }
o1.disposed(by: disposeBag)
subject.onNext("RxSwift")
let o2 = subject.subscribe{ print(">> 2", $0)}
o2.disposed(by: disposeBag)
o2옵저버는 두개의 NextEvent가 전달된 다음에 구독을 시작했기 때문에 이 시점에는 아무런 이벤트도 전달받지 않는다.
다시 서브젝트로 넥스트이벤트를 전달하면
let subject = PublishSubject<String>()
subject.onNext("Hello")
let o1 = subject.subscribe{ print(">> 1", $0) }
o1.disposed(by: disposeBag)
subject.onNext("RxSwift")
let o2 = subject.subscribe{ print(">> 2", $0)}
o2.disposed(by: disposeBag)
subject.onNext("Subject")
//>> 1 next(RxSwift)
//>> 1 next(Subject)
//>> 2 next(Subject)
두 구독자에게 모두 NextEvent가 전달된다.
이어서 서브젝트로 CompletedEvent를 전달해본다.
let subject = PublishSubject<String>()
subject.onNext("Hello")
let o1 = subject.subscribe{ print(">> 1", $0) }
o1.disposed(by: disposeBag)
subject.onNext("RxSwift")
let o2 = subject.subscribe{ print(">> 2", $0)}
o2.disposed(by: disposeBag)
subject.onNext("Subject")
subject.onCompleted()
//>> 1 next(RxSwift)
//>> 1 next(Subject)
//>> 2 next(Subject)
//>> 1 completed
//>> 2 completed
두 옵저버에게 모두 CompletedEvent가 전달된다.
서브젝트가 완료된 이후에 새로운 옵저버가 추가된다면
let subject = PublishSubject<String>()
subject.onNext("Hello")
let o1 = subject.subscribe{ print(">> 1", $0) }
o1.disposed(by: disposeBag)
subject.onNext("RxSwift")
let o2 = subject.subscribe{ print(">> 2", $0)}
o2.disposed(by: disposeBag)
subject.onNext("Subject")
subject.onCompleted()
let o3 = subject.subscribe{ print(">> 3", $0)}
o2.disposed(by: disposeBag)
//>> 1 next(RxSwift)
//>> 1 next(Subject)
//>> 2 next(Subject)
//>> 1 completed
//>> 2 completed
//>> 3 completed
새로운 구독자에게 CompletedEvent가 바로 전달된다.
옵저버블에서 CompletedEvent가 전달된 이후에는 더이상 NextEvent가 전달되지 않는다.
이건 서브젝트도 마찬가지이다. 새로운 구독자에게 전달할 NextEvent가 없기 때문에 곧바로 CompletedEvent를 전달해서 종료하는 것이다.
그렇다면 Subject로 ErrorEvent가 전달되는 경우엔 어떻게 될까.
let subject = PublishSubject<String>()
subject.onNext("Hello")
let o1 = subject.subscribe{ print(">> 1", $0) }
o1.disposed(by: disposeBag)
subject.onNext("RxSwift")
let o2 = subject.subscribe{ print(">> 2", $0)}
o2.disposed(by: disposeBag)
subject.onNext("Subject")
//subject.onCompleted()
subject.onError(MyError.error)
let o3 = subject.subscribe{ print(">> 3", $0)}
o2.disposed(by: disposeBag)
//>> 1 next(RxSwift)
//>> 1 next(Subject)
//>> 2 next(Subject)
//>> 1 error(error)
//>> 2 error(error)
//>> 3 error(error)
CompletedEvent와 마찬가지로 모든 구독자에게 ErrorEvent가 전달된다.
그리고 새로운 구독자에게도 ErrorEvent가 전달된다.
PublishSubject는 이벤트가 전달되면 즉시 구독자에게 전달한다. 그래서
서브젝트가 최초로 생성되는 시점과 첫 번째 구독이 시작되는 시점사이에 전달되는 이벤트는 그냥 사라진다. 이것이 PublishSubject의 대표적인 특징이다.
이벤트가 사라지는 것이 문제가 된다면 다른 서브젝트를 사용하거나 다른 옵저버블을 사용한다.