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
ストリームを購読してそこに書き込むだけです。