
위 Marble diagram에는 세개의 구성요소가 있는데,
Observable은 next 이벤트를 통해 이 각각의 요소들을 방출하는 것이다.

위 Observable은 세개의 tap 이벤트를 방출한 뒤 종료된 completed 이벤트이다.

위의 경우에는 상단의 2개 예시와는 다르게 에러가 발생했다.
완전종료되긴 했지만, error 이벤트를 통해 종료되었다.
정리하자면,
1. Observable은 어떤 구성요소를 가지는
next이벤트를 계속해서 방출할 수 있다.
2. Observable은completed이벤트를 통해서 완전종료 될 수 있다.
3. Observable은error이벤트를 통해서 완전종료 될 수 있다.
let observable:Observable<Int> = Observable<Int>.just(one)
just는 Observable의 타입 메소드로, 오직 하나의 요소를 포함하는 Observable sequence를 생성한다. let observable2 = Observable.of(one, two, three)
of는 주어진 값들의 타입 추론을 통해 Observable sequence를 생성한다. let observable4 = Observable.from([one, two, three])
from은 일반적은 array의 각 요소들을 하나씩 방출한다.일반적으로 구독이라고 말한다.
Observable을 구독하고 싶을 때 subscribe를 선언한다.
Observable은 구독되기 전에는 아무런 이벤트도 발생하지 않는다.
example(of: "subscribe") {
let one = 1
let two = 2
let three = 3
let observable = Observable.of(one, two, three)
observable.subscribe({ (event) in
print(event)
})
/* Prints:
next(1)
next(2)
next(3)
completed
*/
}
.subscribe는 escaping클로저로 Int타입 Event를 갖고 Disposable을 리턴한다.
위 코드에서 Observable은 각 요소들에 대해서 next이벤트를 방출하고 completed를 방출한다.
여기서 next(1)이 아닌, 1이라는 요소만을 방출하고 싶다면 어떻게 해야할까?
observable.subscribe { event in
if let element = event.element {
print(element)
}
}
위 코드와 같은 방법도 있겠지만, 다음의 연산자를 사용하면 보다 편리하다.
observable.subscribe(onNext: { element in
print(element)
})
onNext 클로저는 next 이벤트의 요소만을 처리하고 다른 것은 무시한다.
요소를 갖지 않는 Observable은 empty 연산자를 통해 completed 이벤트만 방출하게 된다.
example(of: "empty") {
let observable = Observable<Void>.empty()
}
observable.subscribe(
// 1
onNext: { element in
print(element)
},
// 2
onCompleted: {
print("Completed")
}
)
.empty와 반대로 절대 종료되지 않는 Observable
무한 지속 시간을 나타내는 데 사용할 수 있다.
example(of: "never") {
let observable = Observable<Void>.never()
observable.subscribe(
onNext: { element in
print(element)
},
onCompleted: {
print("Completed")
}
)
}
example(of: "range") {
// 1
let observable = Observable<Int>.range(start: 1, count: 10)
observable
.subscribe(onNext: { i in
// 2
let n = Double(i)
let fibonacci = Int(
((pow(1.61803, n) - pow(0.61803, n)) /
2.23606).rounded()
)
print(fibonacci)
})
}
range 연산자를 이용해서 start부터 count만큼의 값을 갖는 Observable을 생성한다.subscription.dispose()
요소가 한정되어 있다면 dispose()를 호출하지 않아도 completed가 호출되고 종료되지만, 요소가 무한하다면 dispose()를 호출해야 종료된다.
DisposeBag 타입을 이용할 수 있다.DisposeBag은 disposables를 가지고 있다. example(of: "DisposeBag") {
// 1
let disposeBag = DisposeBag()
// 2
Observable.of("A", "B", "C")
.subscribe{ // 3
print($0)
}
.disposed(by: disposeBag) // 4
}
만약 dispose bag 코드를 추가하거나 수동으로 dispose를 호출하는 것을 하지 않는다면 메모리 누수가 일어날 것이다. 하지만 컴파일러가 경고를 주긴 함...
.next를 통해 Observable을 만들었던 것처럼 .create 연산자를 통해 만들 수도 있다.
example(of: "create") {
let disposeBag = DisposeBag()
Observable<String>.create({ (observer) -> Disposable in
// 1
observer.onNext("1")
// 2
observer.onCompleted()
// 3
observer.onNext("?")
// 4
return Disposables.create()
})
.subscribe(
onNext: { print($0) },
onError: { print($0) },
onCompleted: { print("Completed") },
onDisposed: { print("Disposed") }
).disposed(by: disposeBag)
}
/* Prints:
1
Completed
Disposed
*/
create는 escaping클로저로, AnyObserver를 받고 Disposable을 리턴한다.AnyObserver는 generic타입이다.completed되었기 때문에 3번 주석의 요소는 방출되지 않는다.completed되기 전에 error 이벤트가 방출되었다면 에러를 통해 종료될 것이다.complete, error 모두 방출하지 않고 disposeBag에 어떤 구독도 추가되지 않았다면 종료를 위한 이벤트가 방출되지 않고 따라서 .disposed(by: disposeBag)이 호출되지 못해서 메모리 누수가 발생될 것이다.