中国語で書かれたRxSwiftのドキュメントが非常に参考になりました。
他の方のRxSwiftの勉強に少しでも役に立てばと思い、日本語に翻訳してみました!
今回は3章の「関数型リアクティブプログラミング」となります。
原文: https://beeth0ven.github.io/RxSwift-Chinese-Documentation/content/think_reactive.html
関数型リアクティブプログラミング
関数型リアクティブプログラミング(FRP)はプログラミングパラダイムです。 これは、関数を構築し、それらに応答することによって、データシーケンスを操作するプログラミングの方法です。つまり、リアクティブプログラミングと関数型プログラミングを組み合わせています。
ここで関数型プログラミングを紹介しましょう。
関数型プログラミング
関数型プログラミングは、関数をパラメーターとして渡す、または戻り値とし返すプログラミングパラダイムです。 さまざまな機能を組み合わせることで、望ましい結果を得ることができます。
いくつかの例を見ていきましょう
// 全ての学生
let allStudents: [Student] = getSchoolStudents()
// 3年2組の学生
let gradeThreeClassTwoStudents: [Student] = allStudents
.filter { student in student.grade == 3 && student.class == 2 }
私たちは3年2組の学生を取得したいので、3年2組の判定関数を filter
メソッドに渡しています。これで全ての学生から3年2組の学生をフィルタリングすることができます。
// 3年2組の男子学生が"一剪梅"を歌う
gradeThreeClassTwoStudents
.filter { student in student.sex == .male }
.forEach { boy in boy.singASong(name: "一剪梅") }
同様に、性別を判定する関数を filter
メソッドに渡すことで、3年2組の男子学生をフィルタリングすることができます。そして forEach
メソッドに歌う曲を関数として渡しています。 だから、すべての男性の同級生は "一剪梅" を歌うでしょう😄。
「一剪梅」とは中国の歌のようです。
// 3年2組の学生から90点以上を取った学生を取得し、その親に賞を渡す
gradeThreeClassTwoStudents
.filter { student in student.score > 90 }
.map { student in student.parent }
.forEach { parent in parent.receiveAPrize() }
スコアが90点以上の学生をフィルタリングし、map
を使用して親に変換します。
最後に、forEach
を使って各親に賞を渡しています。
// 3年2組の学生をスコアが高い順に出力する
gradeThreeClassTwoStudents
.sorted { student0, student1 in student0.score > student1.score }
.forEach { student in print("score: \(student.score), name: \(student.name)") }
並べ替えロジックの関数を sorted
メソッドに渡しすことで、学生をスコアが高い順に並び替えすることが出来ます。最後に、forEach
を使用して学生のスコアと名前を出力しています。
関数型プログラミングは、ターゲットの結果を得るために異なるメソッドと異なる機能を組み合わせることができます。従来の for ループを使用して同じロジックを実行するのは退屈です。ですので、関数型プログラミングの利点は明らかです。
- 柔軟である
- 再利用性が高い
- 簡潔である
- メンテナンスが容易
- 様々なニーズの変化に適応
関数型プログラミングの詳細については、《函数式 Swift》を参照してください。
関数型プログラミング -> 関数型リアクティブプログラミング
ここでは、関数型プログラミングを使用してシーケンスを操作する方法について書きます。
たとえば、ボタンクリックイベントをシーケンスとして考えようとします。
// ユーザーが3回ボタンをクリックしたとする
// ボタンクリックシーケンス
let taps: Array<Void> = [(), (), ()]
// 各クリック後のAlertView表示
taps.forEach { showAlert() }
これはクリックイベントの処理に最適ですが、このシーケンス (クリックイベント) の要素が非同期的に生成されるため、従来のシーケンスではそのような要素の非同期生成を記述できないことが問題になります。
この問題を解決するために、Observable<Element>
のシーケンスを生成します。このシーケンスの要素は同期または非同期で生成することができます。
// ボタンクリックシーケンス
let taps: Observable<Void> = button.rx.tap.asObservable()
// 各クリック後のAlertView表示
taps.subscribe(onNext: { showAlert() })
taps
はボタンクリックイベントのシーケンスです。AlertViewの表示は各クリックイベントに応答します。このタイプのプログラミングは、リアクティブプログラミングと呼ばれます。 関数型プログラミングとリアクティブプログラミングに用いることで、関数型リアクティブプログラミングが得られます。
passwordOutlet.rx.text.orEmpty
.map { $0.characters.count >= minimalPasswordLength }
.bind(to: passwordValidOutlet.rx.isHidden)
.disposed(by: disposeBag)
様々なオペレーターを使用して、必要なデータシーケンスを作成することができます。
このシーケンスに対応する適切な方法は 関数リアクティブプログラミング です。
データバインディング(購読)
RxSwift
の重要な概念の1つはデータバインディングです。 監視すべきシーケンスがオブザーバにbindされていることを意味します。
次の2つのコードを比較してみましょう。
let image: UIImage = UIImage(named: ...)
imageView.image = image
非常に精通している最初のコードは、ImageView に別の画像を設定しています。
let image: Observable<UIImage> = ...
image.bind(to: imageView.rx.image)
2つ目のコードは、imageView
にUIImageのシーケンスを "同期" することです。
UIImageのシーケンス は非同期的に生成することが出来ます。
ここで定義されている image
は、上の画像の青色の部分 (Observableシーケンス)、imageView.rx.image
は画像のオレンジ色の部分 (Observer)となります。
この "同期メカニズム" をデータバインディング (購読) と言います。
(翻訳が間違ってたら教えてくださいm(_ _)m)