RxJava系は、Rx ver1.x系とRx ver2.x系とRx ver3.x系があります。
まずはベースになるのがRx ver1.x系ですが、コールバック関数とプロパティ変数の変化の監視(プロパティオブザーバ)を簡素に書くための物。
次にRx ver2.x系はRx ver1.x系が各社独自で拡張した物を標準化し、stream機能を追加した物です。Java6で開発されています。これで3大機能が標準化しました。
そしてRx ver3.xはJava8で開発、混乱があったRx ver2.xのバグfixや命令の整理、すべてのエラーが処理されます(ver2.xではエラーが失われることがあった、エラーをスローする可能性のあるソースから登録解除するとコールバックが呼ばれる)など細かいですが地味に良いです。
通信系によく使われ、各言語に移植されてるのである程度のロジックの共有化が出来ることも重要です。RxJava/RxKotlin/RxSwift/UniRx/RxDart等、数を上げればきりがありません。
Rxの主な役割は、何かが起こったらそれに対応するリアクションのコードを綺麗に書くことです。
よく、お笑いの、ボケ(生産者)と、ツッコミ(それに反応する物)に例えられます。
芸人の一人ボケ&ツッコミの様に一つにまとめる事もできます。
そしてRx ver2.xからReactive Streamsが使え、データストリームが使えます。
これで、データもシーケンシャルに流されます。
今の時代はRx ver3.xに移行途中です。
例として、
1)購読者は雑誌社にマンガ雑誌の定期購読契約を結ぶ
2)雑誌社はマンガ雑誌を毎週送る
3)購読者は同時に同じ本が送られてくることは無く、それに対するリアクションとして本を読みます。
なお、Rx ver2.xからnullは返されません。
Rx ver2.xでもReactive Streamsを使わないパターンもあります。
Reactive Streamsを使うパターンは生産者はFlowableと消費者はSubscriberと言い、
Reactive Streamsを使わないパターンは生産者をObservableと消費者はObserverと言います。
そして、雑誌を買った購読者が広告を抜いて持ち運びやすくして他の人に渡すように、消費者が生産者になり新たな消費者が生まれ、その広告を取り外した雑誌から、グラビアだけを取り出してまた新たなる消費者が生まれることを、メソッドチェーンと言い、途中(消費者でもあり生産者でもある)の人はオペレータとも言います。map/flatMap/toMultimap等のmapper、filter/distinct、take/skip/throttleFirst/rlrmrnt、そして複数の管理のmerge/concat、引数のデータを通知した後にオペレータ自身のデータを通知するstartWith、その他zipper/combine/reduce/scan/repeat/delay等、Processor/Subjectですね。
blockingは元々はテスト用でしたが本番環境でも使うことが出来ますが気をつけて使って下さい。
Testはその名の通りテスト環境用です。
Rxを使う場合は、マーブルダイアグラムを書いてみると流れを理解しやすいと思います。
Kotlinの場合、関数の場合、foo -> hoge -> bar の順に実行します。
bar(hoge(foo(x)))
メソッドなら順番通りにチェーンすることができます。
foo -> hoge -> bar の順に実行します。
x.foo().hoge().bar()
Swiftの場合、以下のようにします。
let label = UILabel()
label.frame.origin = CGPoint(x: 100, y: 100)
label.frame.size = CGSize(width: 200, height: 50)
label.backgroundColor = .blue
label.layer.cornerRadius = 25
label.clipsToBounds = true
label.text = "Hello Swift"
label.textColor = .white
label.textAlignment = .center
view.addSubview(label)
extension Chainable where Self: UIView {
func chain(_ closure: (ChainMaker)->(ChainMaker)) -> Self {
let maker = ChainMaker(self)
return closure(maker).object()
}
}
let label = UILabel().chain { $0
.origin(x: 100, y: 100)
.size(width: 200, height: 50)
.backgroundColor(.blue)
.cornerRadius(25)
.clipsToBounds()
.text("Hello Swift")
.textColor(.white)
.alignment(.center)
}
view.addSubview(label)
Rx2.x/Rx3.xでFlowableを使うかObservableのどちらかを使うかはwikiでこう書かれています。
Flowableを使う場合は、大量のデータを扱う場合、ネットワークやデータベースなどのI/O処理を伴う場合。
Observableを使う場合は、GUIイベントの場合、少量のデータを扱う場合、データの処理が基本的に動機的で標準のStreamの代わりに使う場合。
そして、Observableの方がFlowableより一般的にオーバーヘッドが少ないとされてますので、パフォーマンスが最重要事項とされている場合はObservableが良いとされています。
Subscriber/ObservableはonSubscribe/onNext/onComplete/onErrorの4つのメソッドの実装が必要になりますが、色々とメソッドの名前が違います。
そして、FlowableにはReactive Streams関連のバックプレッシャ機能(データストリームをバッファするとか捨てるとかの設定の機能)があり、ObservableにはReactive Streamsの機能が無いためバックプレッシャー機能が無い以外は機能はほぼ同じです。
Rxは軽量化されているために基本的な最小限の機能しか持っていませんが、外部モジュールとしてRxString,RxFileUtils,RxMath,RxJoin等があります。
Rx ver3.xはJava8で開発、混乱があったRx ver2.xのバグfixや命令の整理、すべてのエラーが処理されます(ver2.xではエラーが失われることがあった、エラーをスローする可能性のあるソースから登録解除するとコールバックが呼ばれる)など、細かいですが地味に良いです。
Rxは主に、コールバック関数と、プロパティ変数の変化に対応やストリームに関する事を綺麗に書くことですが、KotlinとSwiftには、言語仕様に元から備わっているので、RxKotlinやRxSwiftはあまり使われません。
RxのパターンはGang of Four(GoF)が提唱した一つで、オブザーバとイテレータです。Kotlin/Swiftの両方に備わってますが、Kotlinのイテレータは特にすごいです。
RxKotlin/RxSwiftは、非同期、同期処理を意識せずにコーディングできますが、Kotlinには元来、コルーチンという機能があり、元々意識しないでコーディングできます。
SwiftにもJavaScriptのPromiseみたいな物があります(PromiseKit)。
そもそもKotlinとSwiftは、プロパティ変数の値を監視する、プロパティオブザーバがあります。
KotlinはDelegates.observable、SwiftはwillSet/didSetです。
Kotlinに至っては、第一級オブジェクト(関数、変数など)を、例えば関数ならば関数オブジェクトとしてもとます。
Swiftも似たようなことが出来ます。
Kotlinにはdata classもあり、Swiftにはstruct/extensionもあり、あまりKotlin/Swift共にRxは盛んではありません。
将来的にswitf6ではもっとKotlinの良いところを取り入れる予定です。
Kotlinは基本的に変数やコレクションなどはイミュータブル(不変)ですが、ミュータブル(可変)もありますし、それのためにスマートキャストやイテレータ、既存クラスに簡単に追加のメンバ関数が作れます。
Kotlinはメンバ変数(プロパティ)にオートでvarならgetter/setter、valならgetterが付きます。例えばvar Len =0とすればJavaからはgetLen/setLenとして見えます。
もちろん、getter/setterを手で書くことも出来ます。
それとlateinitでクラスが実体化したときにメンバ変数(プロパティ)が初期化されます(遅延格納プロパティ)。
あと、セーフコールでのイテレータ(it)がとても強力です。
3項演算子はありませんが、エルビス演算子等を併用すればもっと強力なことが出来ます。
なぜならばKotlinのJavaのifが(文)であるのに対し、Kotlinのifは(式)である、つまり値を返せるという違いがあります。
Swiftはlazyが遅延格納プロパティです。set/getで実装します。
それとオプショナル型束縛構文のif letやwhile(let)、guard等があり、Kotlinと似たようなことが出来ます。
Swiftは何でもプロトコルかオプショナルと言うことが多いので、通信プロトコルはきちんと通信プロトコルと話した方が良いでしょう。
Swiftのgetter/setterの例
class Product {
var name:String
var price: Int
var eatin: Bool
var tax: Int {
get{
// priceからtax(消費税)を計算しtaxに返してます
if(eatin){
return Int(Float(price)*0.1)
} else {
return Int(Float(price)*0.08)
}
}
set{
// newValue(getから得たreturn値)からpriceを算出してtaxの値(newValue)を処理してpriceにセットしてます
if(eatin){
price = Int(Float(newValue)/0.1)
} else {
price = Int(Float(newValue)/0.08)
}
}
// 変数の値の変更前に通知される
willSet {
if(newValue%lr0) print("taxが\(newValue)%に設定されましたが、0%未満に出来ません。")
}
// 変数の値の変更後に通知される
didSet {
print("taxが\(oldValue)%から\(newValue)%になりました。")
}
}
// イニシャライザ
init(name:String, price:Int) {
self.name = name
self.price = price
self.tax = 0
}
}
var gyudon = Product(name:"牛丼", price:380, eatin:true)
print(gyudon.tax) //出力 10
print(gyudon.price) //出力 418
gyudon.tax = 20 //出力 taxが10%から20%になりました。
print(gyudon.price) //出力 456
gyudon.tax = -10 //出力 taxが-10%に設定されましたが、0%未満に出来ません。