Observable은 observable, observable sequence, sequence 라고도 불린다. Observable은 이벤트를 전달한다. Observer는 이를 감시하고 있다가 전달되는 이벤트를 처리한다. Observable을 감시하는 것을 구독(Subscribe)한다고 표현한다. 그래서 Observer를 Subscriber라고 표현하기도 한다.
일반적으로 메소드, 변수를 정의할 때 한 객체나 컴포넌트 단위로 묶어서 사용된다. 사용할 때도 현재 위치에 포함된 메소드나 변수를 호출해서 사용하면 된다. 하지만 서로 다른 개체에 정보를 전송하려면 어떻게 해야 할까? 이럴 때 공통으로 데이터들을 주고 받을 수 있는 공간을 추상화하고, 이를 통해 서로 규격에 맞춰 정보를 주고 받으면 될 것이다. 이때 사용되는 공간이 이벤트이다. 그래서 이 이벤트에는 단순한 값 뿐만 아니라 사용자와의 인터렉션 등도 포함되며, 객체들 간에 이동이 자유로울 수 있는 것이다.
RxSwift에서는 이 이벤트를 전달하며 정보들을 주고 받는데, 이전 글에서도 설명했던 것처럼, 비동기적 관찰가능한 이벤트를 다룬다. 아래는 민소네님의 블로그에서 Rx를 직접 구현해보기라는 글인데, 제네릭 타입 매개변수를 연관값으로 사용하는 이벤트, 에러 및 완료 케이스 전체를 추상화해서 Event라는 공간을 만드는 것을 볼 수 있다.(실제도 이렇게 구현되어 있다)
enum Event<T> {
case next(T)
case error(Swift.Error)
case completed
}
위에서 살펴본 것처럼 Observable은 세 가지 이벤트를 비동기적으로 전달한다. Next, Error, Completed
Observable에서 발생한 새로운 이벤트는 Next Event 통해서 구독자로 전달된다. 이벤트에 값(숫자나 커스텀한 인스턴스등과 같은 값을 가질 수 있고 탭과 같은 제스처)이 포함되어 있다면 Next Event와 함께 전달된다. RxSwift에서는 이것은 Emission(방출) 이라고 표현한다. Observable의 라이프 사이클 동안 Next Event가 하나도 전달되지 않는 경우가 있고 하나 이상 전달되는 경우도 있다.
Observable에서 에러가 발생하면 Error Event가 전달된다. 반면 정상적으로 종료가 되면 Completed Event가 전달된다. 두 이벤트는 Observable의 라이프 사이클에서 가장 마지막에 전달된다. 이후 Observable이 종료되고 모든 리소스가 정리되기 때문에 다른 이벤트가 전달되지 않는다. 보통 이 두 이벤트는 Emission이라고 부르지 않고 Notification이라고 부른다.
Observable은 생성되어 next 이벤트를 방출하고 상황에 따라 completed, error 이벤트를 notification하고 종료되는 생명주기를 가지고 있다.
"Next Event 통해서 구독자로 전달된다"는 것은 알겠는데, 그렇다면 Observable은 언제 이벤트를 발생하기 시작할까? 또 구독자는 시퀀스를 어디서부터 관찰할 수 있을까? Observable이 하나의 Sequence기 때문에 나오는 질문들이다. 이 질문에 대한 대답에 따라 Hot, Cold로 나뉜다.
주요한 차이점은 다음 두 가지이다.
A “hot” Observable may begin emitting items as soon as it is created, and so any observer who later subscribes to that Observable may start observing the sequence somewhere in the middle.
Hot Observable은 생성되자마다 이벤트를 방출하기 시작합니다. 그리고 나중에 구독한 observer는 sequence의 중간에서부터 관찰할 수 있습니다.
실시간 방송과 같은 느낌. 생성되자마자 계속 방출을 하고 있다. 모든 Observable은 구독을 해야 이벤트를 처리할 수 있기 때문에 구독을 하지 않으면 지난 이벤트들은 모두 버려진다. 그리고 중간부터 구독을 하면 그 이후로 들어오는 이벤트부터 관찰할 수 있다.
스트림을 분기시키는 성질을 가지고 있기 때문에 스트림의 분기가 필요한 경우 Hot Observable을 사용한다. 다시 말해서, 여러 Observer들이 동일한 Observable의 리소스를 공유하고 싶다면 Hot Observable을 사용하자.
A “cold” Observable, on the other hand, waits until an observer subscribes to it before it begins to emit items, and so such an observer is guaranteed to see the whole sequence from the beginning.
Cold Observable은 observer가 구독하기까지 방출을 기다립니다. 그래서 모든 시퀀스의 이벤트를 관찰할 수 있음을 보장합니다.
일반 VOD와 같은 느낌. 생성되어도 구독 전까지는 아무런 이벤트를 방출하지 않는다. 그렇기 때문에 Sequence에 담긴 모든 이벤트를 관찰할 수 있다.
스트림을 분기시키는 성질이 없다. 따라서, Cold Observable을 여러번 Subscribe 하는 경우 Observer마다 별도의 Observable 인스턴스를 가지게 된다. 만약 시퀀스를 만들어 내는 과정이 오래 걸리는 경우, Cold Observable은 구독이 일어날 때 마다 그 과정을 거쳐야 한다.
첫 번째는 create 연산자를 통해서 Observable의 동작을 직접 구현하는 방법이다.
create 연산자는 ObservableType 프로토콜에 선언되어 있는 타입 메소드이다. create 연산자는 클로저에 하나의 파라미터, observer를 받아서 Disposable을 return한다.
Observable<Int>.create { (observer) -> Disposable in
// observer로 next이벤트에 0을 담아서 전달한다. 아래처럼 구현하는 것도 가능.
observer.on(.next(0))
observer.onNext(1)
// 마지막으로 아래 함수를 호출하면 completed 이벤트가 전달되고 Observable이 종료된다.
// 당연히 이후에는 어떤 이벤트도 전달되지 않는다.
observer.onCompleted()
// 마지막으로 Disposable을 리턴한다. Disposable은 메모리 정리에 필요한 객체이다.
return Disposables.create()
}
두 번째 방법은 create가 아닌 다른 연산자를 활용하는 방법이다.
앞에서는 이벤트 전달 코드를 직접 구현했다. 이번에 사용할 연산자는 미리 정의된 규칙에 따라서 이벤트를 전달한다. from 연산자를 활용해서 위의 create 연산자로 만든 Observable과 동일한 이벤트를 전달하는 Observable을 생성해보자.
Observable.from([0, 1])
from 연산자는 파라미터로 전달한 배열에 있는 요소를 순서대로 Eimission하고 completed 이벤트를 전달하는 Observable을 생성한다. 이렇게 단순히 순서대로 방출되는 Observable을 생성할 때는 create보다 from과 같은 다른 연산자를 사용하는 것이 좋다. 이런 연산자가 다양하게 있으니 나중에 더 공부하도록 하자.