4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【iOS, RxSwift】RxSwift入門〜オブザーバーパターンのイメージ〜

Last updated at Posted at 2018-10-21

RxSwiftの入門に際して、まずはオブザーバーパターンを知る必要があります。
ここでは、そのイメージを掴むことを目的としています。

オブザーバーパターンのイメージ

オブザーバーパターンのイメージ

登場人物

  • Observable(監視されるもの)
  • Subscribe(それを購読するもの)
  • イベント

Observable(監視されるもの)

名前の通り監視可能なものを表すクラスがObservableです。
Observableのイメージは川です。
イベントとしてonNext, onError, onComplete が流れてきます。

  • onNext
    デフォルトのイベント
    イベント内に値を格納でき、何度でも呼びせる

  • onError
    エラーイベント
    1度だけ呼ばれ、そのあとはイベントが発生しない

  • onCompleted
    完了イベント
    1度だけ呼ばれ、そのあとはイベントが発生しない

Observable(監視されるもの)

Subscribe(購読する)

イベントを受け取る側は subscribe メソッドでイベントの購読を行います。
Observableを作成することで川ができ、Subscribeでそこに流れてくるイベントを拾うイメージです。

Subscribe(購読する)

イベントを通知する

ObservableとSubscribe により、川とそこに流れるイベントを拾う準備ができました。
あとはそこにイベントを流せばイベントの発生〜受け取りまでの一連の流れができます。

イベントを通知する

Dispose(購読を破棄する)

Disposeは購読を解除(破棄)するためのクラスで、dispose()メソッドを呼ぶことで明示的に購読を破棄するものです。
ObservableをSubscribeしている場合、onError/onCompleted が発生してイベントが終了すると購読解除状態になります。

では購読しているオブジェクト自身が解放されるときはどうでしょうか?
この場合、dispose()メソッドを呼んで購読を解除をしないとずっとメモリを消費してしまい、メモリリークを招きます。
そこで、DisposeBag()という入れ物にインスタンスを格納しておいて、デストラクタで一気に全部disposeする。その役割を担ってくれるのがDisposeBagです。
DisposeBag は Dispose インスタンスを貯め、自身が解放(deinit)され たときに管理している購読を全て自動で解放(unsubscribe)します。

ここまでが基本的なオブザーバーパターンの概要です。

オブザーバーパターンの概要

例えば、以下のようなコードを見てみましょう。

.swift
hogeButton.rx.tap  // ← observable, タップした時にイベントを発生
    .subscribe { [unowned self] _ in // ← 購読
        // ボタンタップ時の処理
    }
    .disposed(by: disposeBag) // 

rx.taprx.text といったものはRxSwifが提供しているObservableであり、例えばrx.tapであればタップのタイミングでイベントが発生されます。
.subscribeによりタップ時のイベントが購読されており、その時の処理を記述します。
そして最後に.disposedを記述することで購読の破棄が行われるようになっています。

【参考】 Obervable と Observerについて

Observable

Observableは名前の通りobserveが可能なものです。
Observableからデータを受け取るにはsubscribe(observer)メソッドを呼びます。このメソッドは引数にObserverのインスタンスを取ります。

RxSwiftでは以下のように定義されています。

.swift
/// 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では以下のように定義されており、データを受け取るためにメソッドが定義されていることがわかります。

.swift
// 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))
    }
}
4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?