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
Next, Error, Completed는 모두 학습한 Event들이다.
Disposed는 Observable이 전달하는 Event는 아니다.
파라미터로 클로저를 전달하면 Observable과 관련된 모든 리소스들이 제거된 뒤에 호출된다.
리소스가 해제되는 시점에 어떤 코드를 실행하고 싶다면 위의 방식으로 작성하고,
나머지는 아래의 방식으로 작성한다.
Observable.from([1, 2, 3])
.subscribe{
print($0)
}
//next(1)
//next(2)
//next(3)
//completed
Observable이 Completed나 Error로 종료되면 리소스정리를 직접하지 않아도 큰 문제는 없다.
하지만 RxSwift문서를 보면 Completed나 Error도 직접 리소스를 정리하라고 나와있다.
리소스에 정리에 사용되는 객체가 Disposable이다.
subscribe의 return형은 Disposable이다.
이 메서드가 return하는 Disposable을 subscriptionDisposable이라고 부르기도 한다.
subscriptionDisposable은 크게 리소스해제와 실행취소에 사용된다.
1. 리소스 해제
//subscribe메서드가 return하는 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")
})
//dispose()실행
subscription1.dispose()
//리소스 해제 방법 1
이렇게 리소스 해제를 할 수 있는데, 이 방법이 아닌 DisposeBag을 사용하는게 권장된다.
RxSwift공식 문서에도 DisposeBag방법을 권장한다.
DisposeBag은 Disposable을 담았다가, 한번에 해제할 수 있다.
Disposable을 담을 때는 disposed(by:) 메서드를 사용한다.
var bag = DisposeBag()
Observable.from([1, 2, 3])
.subscribe{
print($0)
}
.disposed(by: bag)
//이렇게 하면 subscribe가 return하는 Disposable을 bag에 담게 된다.
DisposeBag에 담겨진 Disposable들은 DisposeBag이 해제되는 시점에 함께 해제된다.
위에 선언한 bag이 해제되는 시점에 해제될텐데, 그 이전에 원하는 시점에 해제되게 하고싶다면 아래와 같이 하면 된다.
var bag = DisposeBag()
Observable.from([1, 2, 3])
.subscribe{
print($0)
}
.disposed(by: bag)
bag = DisposeBag()
다시 한번 선언해주면 된다.
리소스를 해제할 때에는 위 코드처럼 DisposeBag을 사용하는 방식으로 구현하는 것이 좋다.
2. 실행취소
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")
})
//1초 간격으로 1씩 증가하는 정수를 방출하는 코드
//Next 0
//Next 1
//Next 2
//Next 3
//Next 4
...
무한정 방출하기 때문에 방출을 중단시킬 수단이 필요하다. 여기에 사용되는 것이 바로 Dispose이다.
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")
})
DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
subscription2.dispose()
})
//Next 0
//Next 1
//Next 2
3초 뒤에 dispose를 호출할 수 있게 코드를 구현한다.
dispose가 호출되는 즉시 모든 리소스가 해제되기 때문에 더이상 이벤트가 전달되지 않는다.
그렇기 때문에 Next다음 CompletedEvent도 호출되지 않는다. 이런 이유로 dispose메서드를 직접 호출하는 것은 가능한 피해야 한다.
특정 시점에 실행을 취소해야 한다면 take, until과같은 연산자를 통해 할 수 있다.