본 게시물은 Florent Pillet, Junior Bontognali, Marin Todorov, Scott Gardner - RxSwift. Reactive Programming with Swift (2017, Razeware LLC) 책과 ReactiveX 사이트를 기반으로 작성되었습니다.
RxSwift를 공부하는 데에 이 책을 읽으면 좋겠다고 생각하였고, 단지 읽기만 하는 것보다 한국어로 직접 정리해놓으면 더 기억하기 좋을 것 같아 게시물을 작성하게 되었습니다.
이번 게시물에서는 마블 다이어그램과, 마블 다이어그램에 해당하는 코드 예시 및 결과를 중점으로 정리하였습니다.
앞서 작성했던 게시물 Chapter 2에서는 Observable이 무엇인지, 어떻게 생성하는지, 어떻게 subscribe하는지, 어떻게 dispose하는지를 배웠습니다. 하지만 보통 앱 개발에서 필요한 것은 실시간으로 Observable에 새로운 값을 수동으로 추가하고 subscriber에게 방출하는 것이 필요합니다. 즉, Observable이자 Observer인 것을 필요로 하는데, 이것이 바로 Subject입니다.
PublishSubject
- 구독한 순간부터 발생하는 새로운 이벤트 수신을 알리고 싶을 때 용이합니다.
- completed나 error 이벤트와 같이 종료 이벤트를 받고 난 이후부터는 completed 이벤트만 방출합니다.
- 현재의 subscriber에게만 이벤트를 방출합니다. 따라서 어떤 이벤트가 발생했을 때, subscribe하지 않은 상태라면 그 값을 얻을 수 없습니다.
- 비어있는 상태로 시작하여 새로운 값만을 방출합니다.
- 실시간 경매 앱처럼 시간에 민감한 데이터를 모델링할 때 용이합니다.
let publishSubject = PublishSubject<String>()
publishSubject.onNext("one")
let subscriptionOne = publishSubject.subscribe(
onNext: { string in
print("1. \(string)")
}
)
publishSubject.onNext("two")
let subscriptionTwo = publishSubject.subscribe(
onNext: { string in
print("2. \(string)")
}
)
publishSubject.onNext("three")
publishSubject.onCompleted()
subscriptionOne.dispose()
subscriptionTwo.dispose()
<결과>
1. two
1. three
2. three
BehaviorSubject
- PublishSubject와 비슷하지만, BehaviorSubject는 초기값이 필요합니다.
- BehaviorSubject는 가장 최근의 next 이벤트를 새로운 구독자에게 방출합니다.
- 초기값/최신값이 필요한 View를 가장 최신의 데이터로 미리 채워놓는 상황에 용이합니다.
let disposeBag = DisposeBag()
let behaviorSubject = BehaviorSubject(value: "one")
behaviorSubject.subscribe {
print("1. \($0)")
}.disposed(by: disposeBag)
behaviorSubject.onNext("two")
behaviorSubject.subscribe {
print("2. \($0)")
}.disposed(by: disposeBag)
behaviorSubject.onNext("three")
<결과>
1. one
1. two
2. two
1. three
2. three
ReplaySubject
내용
- ReplaySubject는 생성할 때 정한 특정 크기만큼 방출하는 최신 element를 일시적으로 버퍼에 저장합니다. 그리고 저장된 element들을 새로운 subscriber에게 방출합니다.
- 주의❗️이렇게 일시적으로 저장된 element들은 메모리가 가지고 있기 때문에, 이미지나 array 같이 메모리를 크게 차지하는 값들을 큰 사이즈의 버퍼로 가지는 것은 메모리에 엄청난 부하를 주게 됩니다.
- 최근 검색어 5개를 보이는 것처럼 최근의 element보다 더 많은 것을 보여주고 싶은 상황에 사용하면 용이합니다.
let disposeBag = DisposeBag()
let replaySubject = ReplaySubject<String>.create(bufferSize: 2)
replaySubject.subscribe {
print("1. \($0)")
}.disposed(by: disposeBag)
replaySubject.onNext("one")
replaySubject.onNext("two")
replaySubject.subscribe {
print("2. \($0)")
}.disposed(by: disposeBag)
replaySubject.onNext("three")
replaySubject.onError(Error)
replaySubject.subscribe {
print("3. \($0)")
}.disposed(by: disposeBag)
<결과>
1. one
1. two
2. one
2. two
1. three
2. three
1. error
2. error
3. two
3. three
3. error
위 결과에서 알 수 있듯이, replaySubject가 종료되었어도 버퍼는 여전히 메모리에 남아있기 때문에 error를 통해 완전 종료시켰음에도 불구하고 새 구독자 3에게 버퍼값을 넘겨줍니다.
따라서 종료시키고 난 다음에는 반드시 dispose하여 이벤트의 재방출을 박아야 합니다.
Variable
- 일반적인 Subject나 Observable와 다르게 onNext(_ :)로 새로운 element를 넣지 않습니다.
- Variable은 에러가 발생하지 않을 것임을 보증합니다. 따라서 error 이벤트를 넣을 수 없습니다.
- Variable은 할당 해제되었을 때 자동으로 완료되기 때문에 수동적으로 completed를 할 필요도, 할 수도 없습니다.
- 현재 value값을 확인하고 싶을 때 유용합니다.
- 제 개인적인 생각으로는 안드로이드의 LiveData와 같은 개념인 것 같습니다.
let disposeBag = DisposeBag()
let variable = Variable("one")
variable.value = "two"
variable.asObservable()
.subscribe {
print("1. \($0)")
}.disposed(by: disposeBag)
variable.value = "three"
<결과>
1. two
1. three
AsyncSubject
- 책에는 없는 내용이지만 ReactiveX 사이트에는 있어서 정리했습니다.
- Subject가 completed 되면 가장 마지막 데이터만을 그때서야 subscriber에게 전달합니다.
- 오류로 인해 종료할 경우에는 발생한 오류만 전달합니다.
'iOS > RxSwift' 카테고리의 다른 글
Ch7. Transforming Operators (0) | 2023.02.24 |
---|---|
Ch5. Filtering Operators (0) | 2023.02.24 |
RxSwift. Traits가 뭘까? (Single, Maybe, Completable) (0) | 2023.02.24 |
Ch2. Observable (0) | 2023.02.24 |
Ch9. Combining Operators (1) | 2021.01.13 |
댓글