Obsevables Observers의 기본 개념 + Disposables , Operator
next , error, completeted
이벤트에는 3가지의 이벤트가 있습니다.
1.next : Observable에서 발생한 새로운 이벤트는 next 이벤트를 통해 구독자(Observer == Subscriber)에게 전달됩니다.
이러한 과정은 RxSwift에서 "Emission"이라 하고 이때 next이벤트는 0 또는 한 개 이상의 이벤트를 전달할 수 있습니다.
2.error: 에러 발생
3.completed: 정상
=>2,3 이벤트는 Observer의 라이프사이클의 가장 마지막에 실행됩니다. 이후 모든 이벤트 종료 따라서 다른 이벤트들은 더 이상 발생되지 않습니다. 이러한 것을 "Notification"이라고 칭합니다.
예시 1. 이벤트 직접 구현 by create연산자
let sample = Observable <Int>. create { (observer) -> Disposable in
observer.on(.next(0)) //구독자에게 전달
observer.onNext(1) // 둘 다 가능
observer.onCompleted() //옵저버블 종료 차후 이벤트 전달 불가
return Disposables.create()
}
예시 2. from연산자는 파라미터를 순서대로 전달합니다.
Observable.from([0,1]) //이렇게 단순히 순서대로 방출되는 옵저버들을 전달할 때는
//create로 직접 구현하는 것보다 from연산자를 활용하는 것이 더 좋습니다
"그러나" 예시 1과 예시 2는 현재 옵저버블이 생성된 상태일 뿐입니다. 왜냐하면 옵저버블은 단순히 이벤트들을 전달하는 순서만을 가리키기 때문입니다. 따라서 구독자와 연결시켜주는 과정이 필요합니다.
sample.subscribe {
//이 클로저로 이벤트가 전달됩니다.
print($0) //next(0) next(1) completed
//element를 통해 next에서 속성을 꺼낼 수 있고 또한 옵서널이기 때문에 옵셔널 바인딩이 필요합니다.
if let elem = $0.element {
print(elem)
}
}
//클로저 파라미터로 속성을 바로 전달합니다 따라서 element속성에 접근할 필요 없습니다.
a.subscribe(onNext: { elem in
print(elem)
})
cf) 옵서버는 동시에 두 개 이상의 이벤트를 처리하지 않습니다. 단지 끊어지지 않고 계속해서 이벤트를 처리할 수 있도록 하는 것입니다.
즉 하나이 이벤트가 처리되어야만 다음 이벤트를 처리할 수 있습니다.
Disposables
Observable.from([1, 2, 3])
.subscribe(onNext: { elem in
print("Next", elem)
}, onError: { error in
print("Error", error)
}, onCompleted: {
print("Completed")
}, onDisposed: {
print("Disposed")
})
출력:
Next 1
Next 2
Next 3
Completed
Disposed
Disposed란 ? 모든 리소스가 제거된 이후 호출.
Observable.from([1, 2, 3])
. subscribe {
print($0)
}
출력:
Next (1)
Next (2)
Next (3)
Completed => Disposed 출력 안됨... 리소스가 제거되지 않은 것인가 생각할 수 있습니다! 하지만
observable이 completed나 error이벤트로 종료되었다면 관련된 리소스는 자동으로 해지됩니다.
그렇다면 왜 출력이 안됐을까? => disposed는 observable이 전달하는 이벤트가 아닙니다. 단지 파라미터로 클로저를 갖고 있는 것일 뿐!따라서 해지 시점에 무언가 작성하고 싶다면 그곳에서 하면 됩니다.
일반적으로 completed 또는 error이벤트로 종료된다면 리소스 정리를 직접 하지 않아도 됩니다.하지만 공식문서는 이경우에도 직접 리소스를 제거하라고 합니다.이때 사용하는 것이 Disposable이라고 합니다.
let subscription1 = Observable.from([1, 2, 3])
.subscribe(onNext: { elem in
print("Next", elem)
}, onError: { error in
print("Error", error)
}, onCompleted: {
print("Completed")
}, onDisposed: {
print("Disposed")
})
subscription1.dispose() //방법 1 => 그러나 공식문서에서는 dispose()를 직접 호출하는것보다 disposeBag을 사용하는 것을 추천합니다.
------------------------------------------------------------------------
추천하는 리소스 제거 방법
var bag = DisposeBag()
Observable.from([1, 2, 3])
.subscribe {
print($0)
}.disposed(by:bag)
------------------------------------------------------------------------
//interval -> 정수를 반환
let subscription2 = Observable<Int>.interval(.seconds(1),
scheduler: MainScheduler.instance)
.subscribe(onNext: { elem in
print("Next", elem)
}, onError: { error in
print("Error", error)
}, onCompleted: {
print("Completed")
}, onDisposed: {
print("Disposed")
})
이 Observable은 1초에 1씩 증가하는 정수를 출력합니다. 무한으로 반복하기때문에
중간에 방출을 중단시킬 수단이 필요합니다 이때 Dispose메소드를 사용합니다.
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
subscription2.dispose()
} //3초 후 중단
출력:
Next 0
Next 1
Next 2
Disposed
이때 즉 3초 후에 모든 리소스가 해지됩니다. 더 이상 이벤트가 전달되지 않습니다.따라서 Completed이벤트는 출력되지 못합니다.이러한 이유로 Dispose 메서드를 직접 호출하는 것은 가능한 피하고 만약 특정 시점에 실행을 취소해야 한다면 take until 연산자를 사용하면 됩니다.