はじめに
私が必要だと思うポイントをまとめたものです。🙇♀️
あとサンプルコードは下の方にずらずら〜〜ってまとめています!
今後何か追記したかったらするかもです!🙇♀️
どうすれば動くの?
難しい感じがしますが『オブザーバブル』と言うオブジェクト、部品みたいなものを作成して、それを実行するための処理を書けば動くと言う感じです。
ちなみに実行するための処理、イベントが返ってくる処理はおそらく2種類!
関数 | もらえるイベント |
---|---|
bind | 値が入っているイベントのみ(next) |
subscribe | 全てのイベント(next, error, completed ) |
難しい感じがしますが基本は以下と思ってます!!
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
Observable作成、それを実行が基本
UILabelにあるプロパティごとObservable作成出来るようにしてくれている。
あとは必要な組み合わせを使うです!
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
宣言したい時
var source:Observable<Int>! ←今回Intだが別にここはInt以外にも入ります!
みたいな感じです!
実際のインスタンス化は
オブザーバブルの作成のとこを参考にしていただければと思います。
入れときたい記述イメージ!
ここは『bind』の例しか書かれていませんが書き方はあまり変わりません!
離しても、繋げてもかけます!
●パターン1
Observable.range(start: 3, count: 5).bind(onNext: {item in
print("🐣!\(item)")
})
●パターン2
let observable = Observable.range(start: 3, count: 5)
observable.bind(onNext: {item in
print("🐣!\(item)")
})
絶対抑えておきたいポイントは?
-
本来もらえられるイベントの種類は3つ!。
-
ただイベント全て返すもの、値が入っているものだけ返すものがある!
エラーなんていらないんだって時はnextだけ返すようにしとけばいいという感じですね!
enum Event<Element> {
case next(Element) //次のデータ
case error(Swift.Error) //エラー!
case completed //コンプリート!
}
『Element』にはIntが入ることも自分で作成したオブジェクトが入ることもありますね。
あと強制解放するsubscription.dispose()
もあるようです。
都度Observable
作成しているような記述の仕方ならsubscription.dispose()
で解放処理が必要そうですね。といってもこれはあんまり使いたくない的なことも書いてます(。・ω・。)??
ちなみに
protocol ObserverType {
func on(_ event: Event<Element>)
}
上記コードの上記onメソッドのはイベントが3つなので
on(.next("sample")) //成功して指定した値が返ってくるやつ!
on(.error(SampleError.sample)) //失敗してエラーが返ってくるやつ!
enum SampleError: Error {
case sample
}
on(.completed) //『おわった======!!!!』が返ってくるやつ!
というものがあるということもわかります!
- 『エラー』や『コンプリート』が呼び出されるまで『次のデータ』を何回も呼べる。
observer.on(.next(strArray))
observer.on(.completed)
observer.on(.next(strArray1)) ← 出力されない(completedが呼び出されるため)
observer.on(.next(strArray)) ← 出力される
observer.on(.next(strArray1)) ← 出力される
observer.on(.completed)
・最終的に作成するObservableはObservableTypeを継承している
public class Observable<Element> : ObservableType {

●オブザーバブルの作成
Create(create generate)
Observableを最初から作成[リンク先サンプルコードあり]
let source : Observable = Observable<Any>.create { observer in
for i in 1...2 {
observer.on(.next(i))
}
observer.on(.completed)
return Disposables.create {
print("disposed")
}
}
source.subscribe {
print($0)
}
//next(1)
//next(2)
//completed
//disposed
Defer(defer)
サブスクライブするまでオブザーバブルを作成しない
🙇♀️defer関数のコードないのでここコード書いてないです。
Empty/ Never/Throw(empty never failWith)
制限されたObservableの作成。以下は空のものを作成したい時の想定サンプルです。
let source = Observable<Any>.empty()
source.subscribe {
print($0)
}
//completed
from(from toObservable)
他オブジェクトの監視を可能にする。[1,2,3]と言う配列渡せば配列の中身が1の次に2と言った感じに順番に返される[リンク先サンプルコードあり]
let numbers = [1,2,3,4,5]
let source = Observable.from(numbers)
source.bind(onNext: { item in
print(item)
})
//1
//2
//3
//4
//5
Interval(interval)
特定の時間間隔で配置された一連の整数を放出するObservableを作成する(timer的なmの)[サンプルコードリンク]
let scheduler = SerialDispatchQueueScheduler(qos: .default)
let source = Observable<Int>.interval(.milliseconds(300), scheduler: scheduler)
source.subscribe { event in
print(event)
}
//next(0)
//next(1)
//next(2)
//next(3)
//next(4)
…続く
Just(just sequenceOf)
他オブジェクトの監視を可能にする。[1,2,3]と言う配列渡せば[1,2,3]と返される[リンク先サンプルコードあり]
let numbers = [1,2,3,4,5]
let source = Observable.just(numbers)
source.bind(onNext: { item in
print(item)
})
//[1, 2, 3, 4, 5]
Range(range)
一連の連続した整数を放出するObservableの作成
Observable.range(start: 3, count: 5).bind(onNext: { event in
print("\(event)")
})
//3
//4
//5
//6
//7
Repeat(repeatElement)
特定のアイテムをずっと放出するオブザーバブルの作成、特定のアイテムは整数でも文字列でもオブジェクトでもって感じかと
Observable.repeatElement(1).bind(onNext: { event in
print("\(event)")
})
//この場合『1』がエンドレスで流れてくる
Start(なし)
Timer(timer)
指定した時間の後にObsevableの作成を行う。以下の場合1秒後に5秒間で数を数えていくというイメージで良さそうです。
let scheduler = SerialDispatchQueueScheduler(qos: .default)
Observable<Int>.timer(1.0, period: 5.0, scheduler: scheduler).subscribe({ event in
print(event)
})
//next(0)
//next(1)
//next(2)
//…続く
●オブザーバブルの変換
Buffer(buffer)
Observableを定期的にまとめて放出するもの。
以下の場合だとrangeメソッドでは3,4,5,6としてるオブザーバブルがあるが、bufferでそれをまとめて放出するようにしている。
ちなみにbufferのtimeSpanはバッファの最大時間長countはバッファの最大要素数とのこと。ようは、3秒までに1つしか流れてこなかったらそのまま流すし、3秒までに10こながれてきても3つまでしかまとめて出さないよとのこと。
これ便利そう!!みんなはボタンのタップとかで使っている模様です!!
let scheduler = SerialDispatchQueueScheduler(qos: .default)
Observable.range(start: 3, count: 5).buffer(timeSpan: 3, count: 3, scheduler: scheduler).bind(onNext: { event in
print("\(event)")
})
//[3, 4, 5]
//[6, 7]
FlatMap(flatMap flatMapWithIndex flatMapFirst flatMapLatest)
Observableによって放出されたアイテムをまとめてObservableにする。
Observableを一回変更して使う時に便利そうです!
Observable.range(start: 3, count: 5).flatMap({ item -> Observable<Int> in
return Observable.create { observer in
observer.on(.next(item + 3))
return Disposables.create()
}
}).bind(onNext: { event in
print("😸\(event)")
})
//😸6 ← 3 + 3になっている
//😸7 ← 4 + 3になっている
//😸8 ← 5 + 3になっている
//😸9 ← 6 + 3になっている
//😸10 ← 7 + 3になっている
GroupBy(なし)
Map(map mapWithIndex)
Observableによって発行されたアイテムを変換。flatMapと似ているがこれはObservable自体を作って返すより中のアイテムをちょこちょこっと変換したい時に使うようですね!
Observable.range(start: 3, count: 5).map { $0 * 5 }.bind(onNext: { event in
print("😸\(event)")
})
//😸15 ← 3 × 5になっている
//😸20 ← 4 × 5になっている
//😸25 ← 5 × 5になっている
//😸30 ← 6 × 5になっている
//😸35 ← 7 × 5になっている
Scan(scan)
Observableによって放出された各アイテムに関数を順次適用
Observable.range(start: 3, count: 5).scan(3, accumulator: { (a, item) in
return a * item
}).bind(onNext: { event in
print("🍰\(event)")
})
//🍰9 ← 3 * 3になっている
//🍰36 ← 9 * 4になっている
//🍰180 ← 36 * 5になっている
//🍰1080 ← 180 * 6になっている
//🍰7560 ← 1080 * 7になっている
Window(window)
項目をある程度分割して放出してくれる。timeSpanはバッファの最大時間長countはバッファの最大要素数。buferと似てるが結果を見ると分かるようにbuferはまとめて出力。これは一つずつ出力するけど分けて出力してくれるといったもの。ある程度出力したらこの処理行うとかで使いそう?ここでは最終を全部文字列で出しているが『completed』部分をifで分けてとか。
let scheduler = SerialDispatchQueueScheduler(qos: .default)
Observable.range(start: 3, count: 5).window(timeSpan: 2, count: 2, scheduler: scheduler).bind(onNext: { event in
event.subscribe({ item in
print("📱\(item)")
})
})
//📱next(3)
//📱next(4)
//📱completed
//📱next(5)
//📱next(6)
//📱completed
//📱next(7)
//📱completed
●オブザーバブルのフィルタリング
Debounce(debounce throttle)
特定の期間が経過した場合にのみ、Observableからアイテムを放出。特定の時間が経過してないのにきたイベントは無視されるみたいですね!!サンプル見比べてもらえるとわかるかと思います!以下の簡単な説明!上記は2秒ごとに数を数えてくが以下はそれを4秒ごとにしたため間に入る1や3が抜けてと言う感じ。
let scheduler = SerialDispatchQueueScheduler(qos: .default)
Observable<Int>.timer(0, period: 2.0, scheduler: scheduler).bind(onNext: { item in
print("\(item)")
})
//0
//1
//2
//3
//4
…続く
let scheduler = SerialDispatchQueueScheduler(qos: .default)
Observable<Int>.timer(0, period: 2.0, scheduler: scheduler).throttle(4.0, scheduler: scheduler).bind(onNext: { item in
print("\(item)")
})
//0
//2
//4
//6
//8
…続く
Distinct(distinctUntilChanged)
Observableによって発行された重複アイテムを抑制。これは便利そうです!以下は連続する値があるところ3が無視されています。注意したいのが以下の場合3が連続した形でなければ、、、、
例えば1,3,2,3ならそのまま1,3,2,3と出力されます。私が勘違いしてしまったの一応報告させていただきました!distinctUntilChanged他もあったのでそっちでは重複アイテムに作用できるかもです。
let numbers = [1,2,3,3,3,4]
let source = Observable.from(numbers).distinctUntilChanged()
source.bind(onNext: { item in
print(item)
})
//1
//2
//3
//4
ElementAt(elementAt)
Observableによって放出されたアイテムnのみを放出します。指定した回数目のイベントだけ拾うと言うものみたいですね。2つめの値だけ取得して使いたいんだ!とかに使うかもしれませんね!
let numbers = [1,2,3,4,5]
let source = Observable.from(numbers).elementAt(3)
source.bind(onNext: { item in
print(item)
})
//4
Filter(filter)
試験合格アイテムのみ出力!mapもそうですがswiftと同じ感じで使います。
let numbers = [1,2,3,4,5]
let source = Observable.from(numbers).filter{ $0 > 2 }
source.bind(onNext: { item in
print(item)
})
//3
//4
//5
First(single)
最初のアイテムのみ出力。
ただこれエラーを握りつぶす処理を書かないといけないとのこと、、、参考→続・takeしてもcompletedにさせない
使う時はご注意ですね!
let numbers = [1,2,3,4,5]
let source = Observable.from(numbers).single().catchError { _ in Observable.never() }
source.bind(onNext: { item in
print(item)
})
//1
IgnoreElements(ありません)
Observableからアイテムを放出せず、終了通知検知用とのこと。ありません。
Last(ありません)
Observableによって放出された最後のアイテムのみを放出。first(single)の逆ですね。ありません。
Sample(sample sampleLatest)
定期的な時間間隔内でObservableによって放出された最新のアイテムを放出します。ん?? この説明で納得しました。→Split laps timer with RxSwift and RxCocoaストップフォッチ的な理解で問題ないかと思います!以下はコードだけで完結したかったのであれですが、sampleの中をボタンのObservableにしたりするといいかもしれません!やってませんが出来るはずです!
let scheduler = SerialDispatchQueueScheduler(qos: .default)
//5秒ごとにタップするとして
let tap = Observable<Int>.timer(0, period: 5.0, scheduler: scheduler)
let source = Observable<Int>.timer(0, period: 0.5, scheduler: scheduler).sample(tap)
source.bind(onNext: { item in
print("🧸\(item)")
})
//🧸0
//🧸10
//🧸20
//🧸30
…続く
Skip(skip)
指定した数だけスキップしてくれるようです。以下だと0,1がスキップされています!最初の方のイベントの気持ちになると、、無視されると思わなかった!ですね!!!
let scheduler = SerialDispatchQueueScheduler(qos: .default)
let source = Observable<Int>.timer(0, period: 1, scheduler: scheduler).skip(2)
source.bind(onNext: { item in
print("🧸\(item)")
})
//🧸2
//🧸3
//🧸4
…続く
SkipLast(ありません)
Take(take)
skipの逆バージョンみたいです。コードなど全く同じぐらいなので省きます。
TakeLast(takeLast)
指定したところから取るといった感じです。コード見てもらった方が早いかもです!
let numbers = [1,2,3,4,5]
let source = Observable.from(numbers).takeLast(3)
source.bind(onNext: { item in
print(item)
})
//3
//4
//5
●オブザーバブルを組み合わせる
And/Then/When(ありません)
CombineLatest(combineLatest withLatestFrom)
アイテムが2つのObservableのいずれかによって発行された場合、指定された関数を介して各Observableによって発行された最新のアイテムを組み合わせ、この関数の結果に基づいてアイテムを発行します。現在の二つのアイテムの状態を使って判断処理した後にその結果を流したい時に使うようです!
let scheduler = SerialDispatchQueueScheduler(qos: .default)
//0.5秒ごとにイベント流す
let item1 = Observable<Int>.timer(0, period: 0.5, scheduler: scheduler)
//2秒ごとにイベント流す
let item2 = Observable<Int>.timer(0, period: 2.0, scheduler: scheduler)
let source = Observable.combineLatest(item1, item2){
item1, item2 in "★\(item1) + ☆\(item2)"
}
source.bind(onNext: { item in
print("🧸\(item)")
})
//🧸★0 + ☆0
//🧸★1 + ☆0
//🧸★2 + ☆0
//🧸★3 + ☆0
//🧸★4 + ☆0
//🧸★4 + ☆1
//🧸★5 + ☆1
//🧸★6 + ☆1
//🧸★7 + ☆1
//🧸★8 + ☆1
//🧸★8 + ☆2
//🧸★9 + ☆2
//🧸★10 + ☆2
//🧸★11 + ☆2
…続く
Join(ありません)
Merge(merge)
subscribe先を同じにする。[リンク先サンプルコードあり]
let source = Observable.of(Observable.from([1,2,3,4,5]), Observable.from(["a", "b", "c", "d", "e"])).merge()
source.bind(onNext: { item in
print("🧸\(item)")
})
//🧸1
//🧸2
//🧸a
//🧸3
//🧸b
//🧸4
//🧸c
//🧸5
//🧸d
//🧸e
StartWith(startWith)
イベント開始前に出力する。ここ沢山指定出来るのいいですね!!ちなみに本来のイベントの型は合わせる必要があるみたいです。って書きましたが型をIntにしてるからって今思いました。
let scheduler = SerialDispatchQueueScheduler(qos: .default)
let source = Observable<Int>.timer(0, period: 1, scheduler: scheduler).startWith(111, 2222, 333)
source.bind(onNext: { item in
print("\(item)")
})
//111
//2222
//333
//0
//1
//2
//3
//4
…続く
Switch(switchLatest)
Observableのアイテムを発行するものに変更するものだと解釈しました。以下コード見比べてもらえたらと思います。
let source = Observable.of(Observable<Int>.just(1))
source.bind(onNext: { item in
print(item)
})
//RxSwift.(unknown context at $10ee7d0f8).Just<Swift.Int>
let source = Observable.of(Observable<Int>.just(1)).switchLatest()
source.bind(onNext: { item in
print(item)
})
//1
Zip(zip)
イベントを合わせてくれるみたいです!
let source = Observable.zip(Observable.from([1,2,3,4,5]), Observable.from(["a", "b", "c", "d", "e"]))
source.bind(onNext: { item in
print("🧸\(item)")
})
//🧸(1, "a")
//🧸(2, "b")
//🧸(3, "c")
//🧸(4, "d")
//🧸(5, "e")
あらかじめある部品について
基本の基本
searchBar.rx.text
extension Reactive where Base : UISearchBar {
public var text: RxCocoa.ControlProperty<String?> { get }
}
このことから、部品が一度『searchBar.rx』で 『Reactive』になることが分かる。
『Reactive』でも使う部品によって呼び出されるものが異なることも理解できる。
何が使えるかは以下のようにその都度探すで問題ないと思っています。
![]() |
---|
サンプルみてみる
pod try RxSwift
にてサンプル見れるみたいなので一番はそれをみながらフムフムした方がいいかと思います!
ちなみにもしエラーになったらpod try RxSwift できない!で修正方法書いたので参考にしていただければと思います。
ちなみに見る場所ですが、『RxSwift/RxExample/RxExample/Examples/』の中色々ですね!
もしプロジェクト起動できない場合はここ見て頂くとフムフムってなるかと思います!!
以下記述はそこに書いてあるほんの一例を書いただけです!
部品.rx.[ここは何があるか] と オブザーバブルの作成の仕方がある程度分かると結構使いこなせそうです!!(。・ω・。)!!
Observable.just([1, 2, 3])
.bind(to: pickerView1.rx.itemTitles) { _, item in
return "\(item)"
}
.disposed(by: disposeBag)
pickerView1.rx.modelSelected(Int.self)
.subscribe(onNext: { models in
print("models selected 1: \(models)")
})
.disposed(by: disposeBag)
Observable.combineLatest(number1.rx.text.orEmpty, number2.rx.text.orEmpty, number3.rx.text.orEmpty) { textValue1, textValue2, textValue3 -> Int in
return (Int(textValue1) ?? 0) + (Int(textValue2) ?? 0) + (Int(textValue3) ?? 0)
}
.map { $0.description }
.bind(to: result.rx.text)
.disposed(by: disposeBag)
参考
以下以外のリンクは必要だと思う所に直接書かさせて頂いています。