Basics
- 모든
Observable
sequence은 단지 sequence이다
- Sequence는 0개 혹은 더 많은 element를 갖을 수 있다.
error
혹은 completed
이벤트를 받을 때, sequence는 더이상 element를 생산해낼 수 없다.
enum _Event<Element> {
case next(Element)
case error(Swift.Error)
case completed
}
protocol _ObserverType {
associatedtype Element
func on(_ event: Event<Element>)
}
protocol _ObservableType {
associatedtype Element
func subscribe<Observer: ObserverType>(
_ observer: Observer
) -> Disposable where Observer.Element == Element
}
class _Observable<Element>: ObservableType {
func subscribe<Observer>(
_ observer: Observer
) -> Disposable
where Observer : ObserverType, Element == Observer.Element {
fatalError()
}
}
Creating
Observable
은 sequence의 생성 방법과 element 요소 생성에 사용되는 parameter를 정의할 뿐이다.
subscribe
메서드가 호출되어야 sequence가 시작된다.
func syncObservable<E>(_ element: E) -> Observable<E> {
return Observable.create { observer in
observer.on(.next(element))
observer.on(.completed)
return Disposables.create()
}
}
func asyncObservable(_ interval: DispatchTimeInterval) -> Observable<Int> {
return Observable.create { observer in
print("Subscribed")
let timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global())
timer.schedule(deadline: DispatchTime.now() + interval, repeating: interval)
let cancel = Disposables.create {
print("Disposed")
timer.cancel()
}
var next = 0
timer.setEventHandler {
if cancel.isDisposed {
return
}
observer.on(.next(next))
next += 1
}
timer.resume()
return cancel
}
}
empty
- element를 하나도 갖지 않는 Observable을 생성한다.
completed
이벤트만 방출한다.
- 즉시 종료할 수 있는 Observable 반환하고자 할 때 시용한다.
Observable<Void>.empty()
.subscribe(
onNext: { print("Element :", $0) },
onCompleted: { print("Completed") }
)
never
completed
이벤트마저 방출되지 않는, 종료되지 않는 Observable을 반환한다.
Observable<Void>.never()
.subscribe(
onNext: { print("Element : ", $0) },
onCompleted: { print("Completed") }
)
deferred
- “연기하다”
- 실제 Observable이 만들어지는 시점을 미룬다.
- Observable을 만들어내는 factory closure를 인자로 받는다.
- 실제로 구독이 일어나는 시점에서야 Observable을 만들어 낸다.
static func _deferred(_ observableFactory: @escaping () throws -> Observable<Element>)
var flag = false
let deferred = Observable<Int>.deferred {
flag.toggle()
return flag ? Observable.from([1, 2, 3]) : Observable.from([4, 5, 6])
}
deferred
.debug()
.subscribe()
.disposed(by: disposeBag)
deferred
.debug()
.subscribe()
.disposed(by: disposeBag)
Disposing
dispose
를 직접 호출하는 것은 bad code smell이 나기 때문에 지양하도록 한다.
DisposeBag
, takeUntil
과 같은 메커니즘을 이용하여 subscription을 dispose하는 것이 더 좋은 방법이다.
dispose
가 호출되면, 해당 seqeunce는 더이상 작동하지 않는다.
- 만일
dispose()
혹은 DisposeBag
에 disposable을 추가하는 등의 행위를 하지 않는다면? Observable이 완료되지 않으면 메모리 누수가 날 것이다.
public protocol _Disposable {
func dispose()
}
Dispose Bags
DisposeBag
이 deallocate될 때, 추가되어져있던 Disposable
들의 dispose
를 호출한다.
dispose
메서드를 갖지 않으며, 즉 명시적인 호출을 허용하지 않는다.
- 바로 정리가 필요할 경우 새롭게 생성한다.
self.disposeBag = DisposeBag()
Hot vs Cold Observable
Hot
- 생성과 동시에 이벤트를 방출하기 시작한다.
- Subscribe 되는 시점과 상관없이 Observer들에게 이벤트를 중간부터 전송한다.
- 생성과 동시에 리소스를 소모한다.
- 여러 Observer가 하나의 Observable을 공유할 수 있다.
ConnectableObservable
로 불리우기도 한다.
- e.g.
.connect()
Cold
- Observer가 Subscribe하는 시점부터 이벤트를 생성하여 방출한다.
- Subscribe되기 전에는 리소스를 소모하지 않는다.
- Observer마다 별도의 Observable 인스턴스를 갖는다.