RxSwiftの入門に際して、まずはオブザーバーパターンを知る必要があります。
ここでは、そのイメージを掴むことを目的としています。
オブザーバーパターンのイメージ
登場人物
- Observable(監視されるもの)
- Subscribe(それを購読するもの)
- イベント
Observable(監視されるもの)
名前の通り監視可能なものを表すクラスがObservableです。
Observableのイメージは川です。
イベントとしてonNext, onError, onComplete が流れてきます。
-
onNext
デフォルトのイベント
イベント内に値を格納でき、何度でも呼びせる -
onError
エラーイベント
1度だけ呼ばれ、そのあとはイベントが発生しない -
onCompleted
完了イベント
1度だけ呼ばれ、そのあとはイベントが発生しない
Subscribe(購読する)
イベントを受け取る側は subscribe メソッドでイベントの購読を行います。
Observableを作成することで川ができ、Subscribeでそこに流れてくるイベントを拾うイメージです。
イベントを通知する
ObservableとSubscribe により、川とそこに流れるイベントを拾う準備ができました。
あとはそこにイベントを流せばイベントの発生〜受け取りまでの一連の流れができます。
Dispose(購読を破棄する)
Disposeは購読を解除(破棄)するためのクラスで、dispose()メソッドを呼ぶことで明示的に購読を破棄するものです。
ObservableをSubscribeしている場合、onError/onCompleted が発生してイベントが終了すると購読解除状態になります。
では購読しているオブジェクト自身が解放されるときはどうでしょうか?
この場合、dispose()メソッドを呼んで購読を解除をしないとずっとメモリを消費してしまい、メモリリークを招きます。
そこで、DisposeBag()という入れ物にインスタンスを格納しておいて、デストラクタで一気に全部disposeする。その役割を担ってくれるのがDisposeBagです。
DisposeBag は Dispose インスタンスを貯め、自身が解放(deinit)され たときに管理している購読を全て自動で解放(unsubscribe)します。
ここまでが基本的なオブザーバーパターンの概要です。
例えば、以下のようなコードを見てみましょう。
hogeButton.rx.tap // ← observable, タップした時にイベントを発生
.subscribe { [unowned self] _ in // ← 購読
// ボタンタップ時の処理
}
.disposed(by: disposeBag) //
rx.tap
やrx.text
といったものはRxSwifが提供しているObservableであり、例えばrx.tap
であればタップのタイミングでイベントが発生されます。
.subscribe
によりタップ時のイベントが購読されており、その時の処理を記述します。
そして最後に.disposed
を記述することで購読の破棄が行われるようになっています。
【参考】 Obervable と Observerについて
Observable
Observableは名前の通りobserveが可能なものです。
Observableからデータを受け取るにはsubscribe(observer)メソッドを呼びます。このメソッドは引数にObserverのインスタンスを取ります。
RxSwiftでは以下のように定義されています。
/// A type-erased `ObservableType`.
///
/// It represents a push style sequence.
public class Observable<Element> : ObservableType {
/// Type of elements in sequence.
public typealias E = Element
init() {
#if TRACE_RESOURCES
let _ = Resources.incrementTotal()
#endif
}
public func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E {
rxAbstractMethod()
}
public func asObservable() -> Observable<E> {
return self
}
deinit {
#if TRACE_RESOURCES
let _ = Resources.decrementTotal()
#endif
}
// this is kind of ugly I know :(
// Swift compiler reports "Not supported yet" when trying to override protocol extensions, so ¯\_(ツ)_/¯
/// Optimizations for map operator
internal func composeMap<R>(_ transform: @escaping (Element) throws -> R) -> Observable<R> {
return _map(source: self, transform: transform)
}
}
Observer
Observableからのデータを受け取るためのクラスです。(流れてくるデータを observeするものです。)
onNext, onError, onCompletedがObservableにより呼び出されます。
RxSwiftでは以下のように定義されており、データを受け取るためにメソッドが定義されていることがわかります。
// Observableからのデータを受け取るものとしてObserverTypeプロトコルを定義
/// Supports push-style iteration over an observable sequence.
public protocol ObserverType {
/// The type of elements in sequence that observer can observe.
associatedtype E
// オブザーバーにイベントを送るためのメソッドを定義
/// Notify observer about sequence event.
///
/// - parameter event: Event that occurred.
func on(_ event: Event<E>)
}
/// Convenience API extensions to provide alternate next, error, completed events
extension ObserverType {
// Observableにより呼び出されるメソッドを定義
/// Convenience method equivalent to `on(.next(element: E))`
///
/// - parameter element: Next element to send to observer(s)
public func onNext(_ element: E) {
on(.next(element))
}
/// Convenience method equivalent to `on(.completed)`
public func onCompleted() {
on(.completed)
}
/// Convenience method equivalent to `on(.error(Swift.Error))`
/// - parameter error: Swift.Error to send to observer(s)
public func onError(_ error: Swift.Error) {
on(.error(error))
}
}