Swift Language
RxSwift
サーチ…
RxSwiftの基礎
FRP、またはFunctional Reactive Programmingには、あなたが知る必要のある基本的な用語がいくつかあります。
すべてのデータはObservableとして表すことができますObservableは非同期データストリームです。 FRPのパワーは、ストリーム、 Observable s、およびそれと連携するための同じインタフェースを提供するようObservable 、同期および非同期イベントを表現しています。
通常Observableは、日付 - .Nextイベントを保持し、正常終了( .Success )またはエラー( .Error )で終了するイベントをいくつか保持します。
大理石の図を見てみましょう:
--(1)--(2)--(3)|-->
この例では、 Int値のストリームがあります。時間が進むにつれて、3つの.Nextイベントが発生し、ストリームは正常に終了しました。
--X->
上記の図は、データが出力されなかった場合を示し、 .ErrorイベントはObservable終了した場合を示しています。
次に進む前に、いくつかの有用な資料があります:
- RxSwift 。例を見て、ドキュメントを読んで始めましょう。
- RxSwift Slackルームには、教育問題解決のためのチャネルがいくつかあります。
- RxMarblesで遊んで 、オペレーターが何をしているのか、そしてあなたのケースで最も有用なものを知ってください。
- この例を見て 、自分でコードを調べてみましょう。
オブザーバブルの作成
RxSwiftはObservableを作成するための多くの方法を提供しています。
import RxSwift
let intObservale = Observable.just(123) // Observable<Int>
let stringObservale = Observable.just("RxSwift") // Observable<String>
let doubleObservale = Observable.just(3.14) // Observable<Double>
したがって、オブザーバブルが作成されます。彼らはただ1つの価値を保持し、その後成功して終了します。それにもかかわらず、それが作成された後に何も起こっていない。どうして?
作業に2つのステップがありObservable S:あなたは、ストリームを作成するために何かを観察し、その後、あなたは、ストリームにサブスクライブまたはそれと対話するために何かにバインドします。
Observable.just(12).subscribe {
print($0)
}
コンソールが印刷します:
.Next(12)
.Completed()
.Nextイベントで行われるデータの操作だけに興味があれば、 subscribeNext演算子を使用しsubscribeNext 。
Observable.just(12).subscribeNext {
print($0) // prints "12" now
}
多くの値の観測値を作成したい場合は、別の演算子を使用します。
Observable.of(1,2,3,4,5).subscribeNext {
print($0)
}
// 1
// 2
// 3
// 4
// 5
// I can represent existing data types as Observables also:
[1,2,3,4,5].asObservable().subscribeNext {
print($0)
}
// result is the same as before.
そして、最後に、 Observableが働きたいと思うかもしれません。たとえば、 Observable<SomeResultType>ネットワーク操作をラップすると便利です。これを達成できるかどうかを見てみましょう:
Observable.create { observer in // create an Observable ...
MyNetworkService.doSomeWorkWithCompletion { (result, error) in
if let e = error {
observer.onError(e) // ..that either holds an error
} else {
observer.onNext(result) // ..or emits the data
observer.onCompleted() // ..and terminates successfully.
}
}
return NopDisposable.instance // here you can manually free any resources
//in case if this observable is being disposed.
}
処分
サブスクリプションが作成された後は、正しい割り当て解除を管理することが重要です。
ドキュメントによって、
シーケンスが一定の時間内に終了した場合、addDisposableTo(disposeBag)を使用してdisposeを呼び出したり使わなかったりしても、永続的なリソースリークは発生しません。ただし、これらのリソースは、要素の作成を完了するか、エラーを返すことによって、シーケンスが完了するまで使用されます。
リソースの割り当てを解除するには、2つの方法があります。
-
disposeBagおよびaddDisposableTo演算子を使用します。 -
takeUntil演算子を使用してtakeUntilます。
最初のケースでは、手動でDisposeBagオブジェクトにサブスクリプションをDisposeBagます。これにより、取り込まれたすべてのメモリが正しくクリアされます。
let bag = DisposeBag()
Observable.just(1).subscribeNext {
print($0)
}.addDisposableTo(bag)
作成したすべてのクラスにDisposeBagを作成する必要はありません.RxSwiftコミュニティのNSObject + Rxプロジェクトを見てください 。フレームワークを使用すると、上記のコードは次のように書き直すことができます:
Observable.just(1).subscribeNext {
print($0)
}.addDisposableTo(rx_disposeBag)
2番目のケースでは、サブスクリプション時間がselfオブジェクトの存続時間と一致する場合、 takeUntil(rx_deallocated)を使用して処分を実装することができます。
let _ = sequence
.takeUntil(rx_deallocated)
.subscribe {
print($0)
}
バインディング
Observable.combineLatest(firstName.rx_text, lastName.rx_text) { $0 + " " + $1 }
.map { "Greetings, \($0)" }
.bindTo(greetingLabel.rx_text)
アイテムが2つのObservablesいずれかによって放出されるたびにcombineLatest演算子を使用して、各Observableによって放出された最新のアイテムを結合します。このようにして、2つのUITextFieldの結果を組み合わせて、新しいメッセージを文字列補間を使って"Greetings, \($0)"というテキストに結合し、後でUILabelテキストにバインドします。
非常に簡単にUITableViewとUICollectionViewにデータをバインドできます。
viewModel
.rows
.bindTo(resultsTableView.rx_itemsWithCellIdentifier("WikipediaSearchCell", cellType: WikipediaSearchCell.self)) { (_, viewModel, cell) in
cell.title = viewModel.title
cell.url = viewModel.url
}
.addDisposableTo(disposeBag)
それはcellForRowAtIndexPathデータソースメソッドの周りのRxラッパーです。また、Rxは従来の意味で必須のメソッドであるnumberOfRowsAtIndexPath実装を担当しますが、ここで実装する必要はありません。
RxCocoaとControlEvents
RxSwiftは、データを制御する方法だけでなく、反応的な方法でユーザーの行動を表現する方法も提供します。
RxCocoaには必要なものがすべて含まれています。ほとんどのUIコンポーネントのプロパティをObservableにラップしますが、実際はそうではありません。いくつかのアップグレードがありObservableと呼ばれるS ControlEventと(イベントを表す)■ ControlProperties (驚き、プロパティを表します!)。これらのものはObservableストリームをボンネットの下に保持しますが、いくつかのニュアンスもあります。
- 決して失敗しないので、エラーはありません。
- それは割り当て解除されているコントロールのシーケンスを
Completeます。 - メインスレッド(
MainScheduler.instance)でイベントを配信します。
基本的には、通常どおりに作業できます。
button.rx_tap.subscribeNext { _ in // control event
print("User tapped the button!")
}.addDisposableTo(bag)
textField.rx_text.subscribeNext { text in // control property
print("The textfield contains: \(text)")
}.addDisposableTo(bag)
// notice that ControlProperty generates .Next event on subscription
// In this case, the log will display
// "The textfield contains: "
// at the very start of the app.
これは非常に重要です:あなたがRxを使う限り、 @IBActionことを忘れて、必要なものを一度にバインドして設定することができます。たとえば、View ControllerのviewDidLoadメソッドは、UIコンポーネントの動作を記述するのに適しています。
別の例:テキストフィールド、ボタン、ラベルがあるとします。ボタンをタップすると、 テキストフィールド内のテキストを検証し、その結果をラベルに表示する必要があります 。うん、別の検証電子メールタスクのようだね?
まず、 button.rx_tapを取得しbutton.rx_tap 。ControlEvent:
----()-----------------------()----->
ここで空の括弧はユーザータップを示します。次に、 withLatestFrom演算子をwithLatestFromしてtextFieldに書かれた内容をwithLatestFromます( ここでは、上のストリームはユーザーのタップを表し、下の1つはテキストフィールドのテキストを表しているとします)。
button.rx_tap.withLatestFrom(textField.rx_text)
----("")--------------------("123")--->
// ^ tap ^ i wrote 123 ^ tap
ニース、検証する文字列があり、検証が必要なときにだけ出力されます。
Observableはmapやfilterなどの慣れ親しんだ演算子がありますが、 mapを使ってテキストを検証します。 validateEmail関数を自分で作成し、必要な正規表現を使用します。
button.rx_tap // ControlEvent<Void>
.withLatestFrom(textField.rx_text) // Observable<String>
.map(validateEmail) // Observable<Bool>
.map { (isCorrect) in
return isCorrect ? "Email is correct" : "Input the correct one, please"
} // Observable<String>
.bindTo(label.rx_text)
.addDisposableTo(bag)
完了!より多くのカスタムロジックが必要な場合(エラーの場合にエラービューを表示したり、成功すれば別の画面に移行するなど)、最後のBoolストリームを購読してそこに書き込むだけです。