SwiftBondの作者さんが作った新ライブラリ「ReactiveKit」を使ってみた
SwiftBondの作者である@srdanrasicさんが、ReactiveKitというライブラリを開発していました。
この記事を投稿した(2015/11)時点で、スター数が30弱しかないです。
READMEを少し見てみたところ、ほぼSwiftBondですが、OperationというRxのObservableのようなものが追加されているようです。その他も少し変わっているっぽい?
ということで検証してみました。
※ 今回検証するバージョンは「1.0.4」です。
Observable
Basic
SwiftBondと同じですね。
let value1 = Observable(1)
let value2 = Observable(2)
print(value2.value) // => 2
value1.bindTo(value2) // バインド
print(value2.value) // => 1
value1.next(7)
print(value2.value) // => 7
UIKit
ReactiveUIKitをimportすることでUIKitのObservableプロパティを使用することも可能です。ViewのプロパティとViewModelのプロパティのバインドするのに便利です。
textField.rText.bindTo(label)
textField.rText.bindTo(viewModel.emailAddress)
Collection
配列はObservableCollectionを使います。
var list = ObservableCollection([Int]())
list.observe{e in
print("array: \(e.collection), inserts: \(e.inserts)")
}
list.append(10) // => array: [10], inserts: [0]
list.append(10) // => array: [10, 10], inserts: [1]
Operation
さらっと見た感じRxのObservableと同じようなものっぽいです。
Operationの作成
ReactiveXのcreateメソッドと同じです。Operation構造体のイニシャライザにオブザーバーがセットされた時の処理を記述したクロージャを渡します。返り値にはDisposableType?を指定する必要があります。BlockDisposableを使うとdisposeされた時の処理をかけるっぽい。
let operation = Operation {(observer: OperationObserver<NSData, NSError>) in
let request = Alamofire.request(.GET, url: url).response { _, _, data, error in
if let error = error {
observer.failure(error)
} else {
observer.next(data)
observer.success()
}
}
return BlockDisposable {
request.cancel()
}
}
let disposable = operation.observe(on: Queue.main.context){event in
switch event{
case .Next(let value):
print(value)
case .Failure(let error):
print("エラーハンドリング \(error)")
case .Success:
print("Success")
}
}
上記のコードは、オブザーバーがセットされた時にAlamofireでAPIを叩いて結果が返ってきた時にオブザーバーにイベントを伝える例です。リクエストキャンセルするには
disposable.dispose()
とすれば良いです。
うーん、めっちゃRxSwiftに似ているなぁ。
StreamTypeとObservableとOperation
ObservableはObservableTypeに適合しており、OperationはOperationTypeに適合しています。さらに、ObservableTypeとOperationTypeは共にStreamTypeに適合しています。
つまり、ObservableやOperationに使えるメソッドはStreamTypeのProtocol Extensionで実装されているものがほとんどです。
メソッドは、Rxでよく見るmapやfilterやthrottleやzipなどなどです。
ReaciveKit = SwiftBond + RxSwift って感じなのかなーと個人的には思っています。
ライブラリのコード読んでいると基本的にSwiftBondのコードを流用しつつ新しい要素取り入れていってる感じでした。
おまけ
StreamType ProtocolのExtensionで実装されているzipメソッドが凄かった
@warn_unused_result
public func zip<A: StreamType, B: StreamType, C: StreamType, D: StreamType, E: StreamType, F: StreamType, G: StreamType, H: StreamType, I: StreamType, J: StreamType, K: StreamType>
( a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, _ g: G, _ h: H, _ i: I, _ j: J, _ k: K) -> Stream<(A.Event, B.Event, C.Event, D.Event, E.Event, F.Event, G.Event, H.Event, I.Event, J.Event, K.Event)>
{
return zip(a, b, c, d, e, f, g, h, i, j).zipWith(k).map { ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $1) }
}