# [RxSwift] Subjects
(실제 앱 구동시) run time시에 Observable에 값을 추가하여 emit이 발생하게끔 해주는 대리인
Observable에 값을 추가하는 대상은 Observer라 부르며(추상적인 개념), Observable과 Observer 기능을 둘 다 하는 것이 바로 Subjects.
# PublishSubjects
empty상태로 시작, 새로운 이벤트만 subscriber에게 emit. 구독된 순간 새로운 이벤트 수신을 알리고 싶을때 사용. 시간에 민감한 데이터를 모델링 할 경우(실시간 경매 앱 - 10:00am 경매 시작일 경우, 10:01am에 접속했을 때 알림이 보내질 필요가 없는 경우)
example(of: "PublishSubject") {
let subject = PublishSubject<String>()
subject.onNext("Is anyone listening?")
let subscriptionOne = subject
.subscribe(onNext: { (string) in
print(string)
})
subject.on(.next("1")) //Print: 1
subject.onNext("2") //Print: 2
}
-> 출판사에서 "Is Anyone Listening?"이란 내용 받음(.onNext)
-> 구독(.subscribe)
-> 현재 벌어진 일만 emit함(.subscribe했을 경우 "Is anyone listening?"은 과거에 발생했던 일이라 emit하지 않음)
-> 뒤에 1과 2 이벤트 추가시(현재 벌어진 일), 이것들은 emit함
# BehaviorSubject
하나의 초기값으로 시작, 최신 값(.next)만 새로운 subscriber에게 emit. 뷰를 가장 최신의 데이터로 미리 채우기에 용이(유저 프로필 화면을 BehaviorSubject에 바인딩)
enum MyError: Error {
case anError
}
example(of: "BehaviorSubject") {
// 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
버퍼 사이즈를 지정하며, 버퍼 사이즈만큼 새로운 subscriber에게 emit
example(of: "ReplaySubject") {
let subject = ReplaySubject<String>.create(bufferSize: 2)
let disposeBag = DisposeBag()
subject.onNext("1")
subject.onNext("2")
subject.onNext("3")
subject
.subscribe {
print("1)", $0)
}
.disposed(by: disposeBag)
/* prints
1) next(2)
1) next(3)
*/
subject
.subscribe {
print("2)", $0)
}
.disposed(by: disposeBag)
/* prints
2) next(2)
2) next(3)
*/
subject.onNext("4")
/* prints
1) next(4)
2) next(4)
*/
subject.onError(MyError.anError)
/* prints
1) error(anError)
2) error(anError)
*/
// subject.dispose()
subject.subscribe {
print("3)", $0)
}
.disposed(by: disposeBag)
/* prints:
3) next(3)
3) next(4)
3) error(anError)
*/
}
# PublishRelay, BehaviorRelay
오직 .next 이벤트만 emit함 (.completed, .error무시, non-terminating에서 유용하게 사용)
PublishRelay : PublishSubject를 단순히 wrap한 것이며 .next만 가능하고 기능 동일
BehaviorRelay : BehaviorSubject를 단순히 wrap한 것이며 .next만 가능하고 기능 동일 realy의 핵심은 절대 끝나지 않음을 보장하는 것
import RxSwift
import RxCocoa // 필요
example(of: "PublishRelay") {
let relay = PublishRelay<String>()
let disposeBag = DisposeBag()
relay.accept("Knock knock, anyone home?")
relay
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
relay.accept("1") // print: 1
// error와 onCompleted()사용 불가
// relay.accept(MyError.anError)
// relay.onCompleted()
}
- relay의 추가는 .accept()로 접근
- error, onCompleted() 사용 불가
import RxSwift
import RxCocoa
example(of: "BehaviorRelay") {
let relay = BehaviorRelay(value: "Initial value")
let disposeBag = DisposeBag()
relay.accept("New initial value")
relay
.subscribe {
print("1)", $0)
}
.disposed(by: disposeBag)
// print : 1) next(New initial value)
// 1
relay.accept("1")
// print : 1) next(1)
// 2
relay
.subscribe {
print("2)", $0)
}
.disposed(by: disposeBag)
// print : 2) next(1)
// 3
relay.accept("2")
/* prints
2) next(2)
*/
}
.accept()로 다가가며 error, onCompleted를 못 쓴다는 것만 제외하면 BehaviorSubject와 동일