はじめに
RxSwiftについて学んだことを自分なりにまとめていこうかと思います。
GitHub
用語
Reactive Extensions
オブザーバーパターン、イテレーターパターン、関数型プログラミングの概念を実装したインターフェース。
オブザーバーパターン
プログラミング内にあるオブジェクトのイベントを他のオブジェクトへ通知する処理で使われるデザインパターンの一種。
RxSwift
Reactive Extensionsの概念をSwiftで扱えるようにした拡張ライブラリ。
GitHub
RxCocoa
Reactive Extensionsの概念をUIKitで扱えるようにした拡張ライブラリ。
リアクティブプログラミング
「時間と共に変化する値」と「振る舞い」の関係を宣言的に記述するプログラミングの手法。
ストリーム
時間順に並んだ進行中のイベントのこと
マーブルダイアグラム
RxSwiftの特徴
メリット
値の変化が検知しやすい
非同期処理が簡潔に書ける
時間経過に関する処理をシンプルに書ける
コード全体が一貫する
まとまった流れが見やすい
差分がわかりやすい
処理スレッドを変えやすい
コールバックを減らせる(インデントの浅いコードにできる)
デメリット
学習コストが高い
デバッグしにくい
RxSwiftの導入手法
CocoaPods, Carthage, SwiftPackageManagerなどがある。
RxSwiftの基本的な書き方
以下のように、メソッドチェーンで書くことができます。
loginButton.rx.tap
.subscribe(onNext: { [weak self] in
//処理
})
.disposed(by: disposeBag)
詳細な説明は後述しますが、大まかな流れは以下のようになります。
1.ストリームの購読
2.ストリームにイベントが流れてきた時にどうするかを定義
3.クラスが破棄されると同時に購読を破棄させるように設定
実際に書いてみる
実際に書いたコードはGitHubにあげておきます。今回のコードはSimpleRxSwiftフォルダにあります。
RxSwiftを使わない場合はこんな感じになると思います。
import UIKit
class SimpleViewController: UIViewController {
@IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func loginButtonDidTapped(_ sender: Any) {
label.text = "login"
}
@IBAction func messageButtonDidTapped(_ sender: Any) {
label.text = "message"
}
@IBAction func logoutButtonDidTapped(_ sender: Any) {
label.text = "logout"
}
@IBAction func backButtonDidTapped(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
}
このような書き方は、1つのボタンに1つの関数を定義しています。
ボタンが4つなら関数は4つ用意します。
しかし、RxSwiftでは以下のように書きます。
import UIKit
import RxSwift
import RxCocoa
class RxSimpleViewController: UIViewController {
@IBOutlet weak var label: UILabel!
@IBOutlet weak var loginButton: UIButton!
@IBOutlet weak var messageButton: UIButton!
@IBOutlet weak var logoutButton: UIButton!
@IBOutlet weak var backButton: UIButton!
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
loginButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.label.text = "login"
})
.disposed(by: disposeBag)
messageButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.label.text = "message"
})
.disposed(by: disposeBag)
logoutButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.label.text = "logout"
})
.disposed(by: disposeBag)
backButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.dismiss(animated: true, completion: nil)
})
.disposed(by: disposeBag)
}
}
処理は全く同じでが、コードが全然違いますよね。使わない場合と比べて、UIとコードの制約を一つのプロパティの結合で済むようになっているため、緩くできました。
おわりに
次回
RxSwift難しい、、、
