はじめに
そろそろ勉強しなきゃという思いとRxSwiftを触ってみたいなという思いがぶつかってQiita書こうと思いました。
そもそもRxって?
Reactive Extensions
の略称でリアクティブプログラミング
を実現するための
設計パターン及び、ライブラリを指します。
元々は、マイクロソフトが自社製品に組み込んでいる.NETフレームワークに向けて開発した.NET用のライブラリ(Rx.NET
)でしたが、あまりにも強力な技法だったので色んな言語に波及していきました。
それがSwiftにも波及してきてRxSwift
が開発されました。
リアクティブプログラミングとは
難しく感じますが、エクセル
やスプレッドシート
をイメージすると分かりやすいです。
例えば、このように
A1=1
B1=2
の値を入力してC1に=A1+B1
という関係を入力します。
すると瞬時に計算が走って値が出力されました。
B1
の値を変えたとしても、A1
の値を変えたとしてもC1
に計算の答えが瞬時に出力されます。
このような動きが正にリアクティブプログラミング
と言われています。
リアクティブプログラミングは時間軸を重視した
プログラミング方法となっており
プログラム内での値の変化を時間軸で捉え、値が変わったというイベントによって処理を行います
。
先ほどのエクセルやスプレッドシートの例を図にするとこんな感じ↓
左から右に時間が流れ、そこにイベントが流れてきます。
ここではAもしくはBの値が変化したというイベント
が流れます。
そして、イベントが発生したらA+B=C
という処理が走っています。
上記の図は、正式名称がありマーブルダイアグラム
と呼ばれています。
下記のサイトに色んなオペレーター(演算)によるマーブルダイアグラムの図が
載っていますので見てみて下さい↓
RxMarbles
このようにマーブルダイアグラムでは時間順に並んだ進行中のイベント
が流れており
これらをストリーム
と呼びます。
Observer(オブザーバー)パターン
Observerパターン
はRxの根幹となる考え方です。
この考え方には観測対象
と観測者
の2つの役割が存在しています。
観測対象を観測者が観測していて、観測対象の何らかのイベントを観測者が確認したら特定のアクションを起こす
というのが基本の考え方となっています。
ただ実際に実装する際は観測対象に観測者を登録して、観測対象でイベントが発生したら観測者に知らせて特定のアクションを起こす
といった流れになります。
ここでいうイベントは、ボタンがタップされた
・文字が入力された
・APIから値が取得できた
等、プログラム内におけるオブジェクトの状態変化すべて
を指します。
ObservableとObserver
Observerパターンでは次の2つのクラスでストリーム
を扱います。
・Observable: ストリームを表現するクラス
・Observer: Observableからストリームを受け取るクラス
subscribe
Observableはsubscribeメソッド
を持っています。
これは何なのかというと、通知先を登録するメソッド
です。
つまり、Observableに対してObserverを登録するメソッド
ですね。
※Observableを監視
することをsubscribeとも呼んでいます。
先ほどの図で表すとこんな感じ↓
Observableが通知するイベント
Observableが通知するイベントは3種類あり、enumで定義されています。
これらのイベントをObserverが受け取ります。
public enum Event<Element> {
// 通常のイベントを通知、値を渡すことができる
// 複数回送れる
case next(Element)
// エラーの発生を通知
// 発生後はイベントが一切発生しない
case error(Error)
// 完了を通知、値を渡せない
// 発生後はイベントが一切発生しない
case completed
}
図に表すとこんな感じ↓
実際にコードで書くとこのようになります↓
let observable = textField.rx.text.orEmpty.asObservable()
observable.subscribe(onNext: { text in
print(text)
}, onError: { error in
print(error)
}, onCompleted: { _ in
print("完了")
})
コードを見てみると流れてきたイベントに対する処理をObservableに登録
しているという見方もできます。
そして、注意して欲しいのが一度、onCompleted
やonError
が発生すると
それ以降はonNext
を呼ぶことが出来ません。
Disposable
Observableをsubscribeすると、Disposable
というものを返します。
これは、subscribeしたObservableをunsubscribe
するための仕組みで
無視するとsubscribeした処理が永遠に解放されずにメモリリークに繋がる恐れ
があります。
その解決策としてDisposeBag
というものがあります。
これは内部でDisposableを貯めておいて
自身が解放された時に保持しているDisposableを廃棄
してくれます。
Observableはdisposeメソッド
を持っており、呼び出してDisposeBagを代入する事によって
subscribe時に返されるDisposableをDisposeBagに貯める処理
を定義しています。
public func disposed(by bag: DisposeBag) {
// selfがDisposableのこと
bag.insert(self)
}
実際に先ほどのコードで使用した場合↓
// DisposeBagを初期化する
let dispoceBag = DisposeBag()
let observable = textField.rx.text.orEmpty.asObservable()
observable.subscribe(onNext: { text in
print(text)
}, onError: { error in
print(error)
}, onCompleted: { _ in
print("完了")
// 最後にメソッドを呼ぶ
}).disposed(by: dispoceBag)
循環参照に注意する
subscribe時の処理の中のクロージャはselfを強参照
すると
解放されなくなってしまいます。
なのでselfを弱参照
しましょう。
let dispoceBag = DisposeBag()
let observable = textField.rx.text.orEmpty.asObservable()
// weakキーワードでselfを弱参照にする
observable.subscribe(onNext: {[weak self] text in
print(text)
}, onError: { error in
print(error)
}, onCompleted: { _ in
print("完了")
}).disposed(by: dispoceBag)
おわりに
キリがいいのでここで終わります。次回もいつか書こうと思います。
間違っている部分や説明が足りない部分はコメントして教えて下さると有り難いです。
参考記事
【Swift】RxSwift勉強してみたPart4
【RxSwift】Singleton で DisposeBag を使うことの考察
RxSwiftについてようやく理解できてきたのでまとめることにした(1)
SwiftでReactive Programming - Qiita
Rx入門 (2) - オブザーバーパターン - xin9le.net
RxSwiftでiOSアプリ開発~リアクティブプログラミングを導入する - CodeZine