14
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Rxswift] 基本、作成、変換、フィルタリング、組み合わせ、サンプルコード

Last updated at Posted at 2020-05-06

はじめに

私が必要だと思うポイントをまとめたものです。🙇‍♀️
あとサンプルコードは下の方にずらずら〜〜ってまとめています!
今後何か追記したかったらするかもです!🙇‍♀️

どうすれば動くの?

難しい感じがしますが『オブザーバブル』と言うオブジェクト、部品みたいなものを作成して、それを実行するための処理を書けば動くと言う感じです。

ちなみに実行するための処理、イベントが返ってくる処理はおそらく2種類!

関数 もらえるイベント
bind 値が入っているイベントのみ(next)
subscribe 全てのイベント(next, error, completed )

難しい感じがしますが基本は以下と思ってます!!

☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
Observable作成、それを実行が基本
UILabelにあるプロパティごとObservable作成出来るようにしてくれている。
あとは必要な組み合わせを使うです!
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆

宣言したい時

.swift
var source:Observable<Int>! ←今回Intだが別にここはInt以外にも入ります

みたいな感じです!
実際のインスタンス化は
オブザーバブルの作成のとこを参考にしていただければと思います。

入れときたい記述イメージ!

ここは『bind』の例しか書かれていませんが書き方はあまり変わりません!
離しても、繋げてもかけます!

●パターン1

.swift
Observable.range(start: 3, count: 5).bind(onNext: {item in
    print("🐣!\(item)")
})

●パターン2

.swift
let observable = Observable.range(start: 3, count: 5)

observable.bind(onNext: {item in
    print("🐣!\(item)")
})

絶対抑えておきたいポイントは?

  • 本来もらえられるイベントの種類は3つ!。

  • ただイベント全て返すもの、値が入っているものだけ返すものがある!
    エラーなんていらないんだって時はnextだけ返すようにしとけばいいという感じですね!

.swift

enum Event<Element>  {
    case next(Element)      //次のデータ
    case error(Swift.Error) //エラー!
    case completed          //コンプリート!
}

『Element』にはIntが入ることも自分で作成したオブジェクトが入ることもありますね。
あと強制解放するsubscription.dispose()もあるようです。
都度Observable作成しているような記述の仕方ならsubscription.dispose()で解放処理が必要そうですね。といってもこれはあんまり使いたくない的なことも書いてます(。・ω・。)??

ちなみに

.swift
protocol ObserverType {
    func on(_ event: Event<Element>)
}

上記コードの上記onメソッドのはイベントが3つなので

.swift
on(.next("sample")) //成功して指定した値が返ってくるやつ!

on(.error(SampleError.sample)) //失敗してエラーが返ってくるやつ!

enum SampleError: Error {
    case sample
}

on(.completed) //『おわった======!!!!』が返ってくるやつ!

というものがあるということもわかります!

  • 『エラー』や『コンプリート』が呼び出されるまで『次のデータ』を何回も呼べる。
.swift
observer.on(.next(strArray))
observer.on(.completed)
observer.on(.next(strArray1)) ← 出力されない(completedが呼び出されるため)
.swift
observer.on(.next(strArray))  ← 出力される
observer.on(.next(strArray1)) ← 出力される
observer.on(.completed)

・最終的に作成するObservableはObservableTypeを継承している

.swift
public class Observable<Element> : ObservableType {

:older_man_tone1:以下はオブザーバブルあれこれは主に[ここ](http://reactivex.io/documentation/operators.html)を参考にしています!

●オブザーバブルの作成

Create(create generate)

Observableを最初から作成[リンク先サンプルコードあり]

.swift
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の作成。以下は空のものを作成したい時の想定サンプルです。

.swift
let source = Observable<Any>.empty()

source.subscribe {
    print($0)
}

//completed

from(from toObservable)

他オブジェクトの監視を可能にする。[1,2,3]と言う配列渡せば配列の中身が1の次に2と言った感じに順番に返される[リンク先サンプルコードあり]

.swift
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の)[サンプルコードリンク]

.swift
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]と返される[リンク先サンプルコードあり]

.swift
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の作成

.swift
Observable.range(start: 3, count: 5).bind(onNext: { event in
    print("\(event)")
})

//3
//4
//5
//6
//7

Repeat(repeatElement)

特定のアイテムをずっと放出するオブザーバブルの作成、特定のアイテムは整数でも文字列でもオブジェクトでもって感じかと

.swift
Observable.repeatElement(1).bind(onNext: { event in
    print("\(event)")
})

//この場合『1』がエンドレスで流れてくる

Start(なし)

Timer(timer)

指定した時間の後にObsevableの作成を行う。以下の場合1秒後に5秒間で数を数えていくというイメージで良さそうです。

.swift
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つまでしかまとめて出さないよとのこと。
これ便利そう!!みんなはボタンのタップとかで使っている模様です!!

.swift
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を一回変更して使う時に便利そうです!

.swift
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自体を作って返すより中のアイテムをちょこちょこっと変換したい時に使うようですね!

.swift
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によって放出された各アイテムに関数を順次適用

.swift
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で分けてとか。

.swift
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が抜けてと言う感じ。

.swift
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
続く
.swift
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他もあったのでそっちでは重複アイテムに作用できるかもです。

.swift
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つめの値だけ取得して使いたいんだ!とかに使うかもしれませんね!

.swift
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と同じ感じで使います。

.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にさせない
使う時はご注意ですね!

.swift
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にしたりするといいかもしれません!やってませんが出来るはずです!

.swift
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がスキップされています!最初の方のイベントの気持ちになると、、無視されると思わなかった!ですね!!!

.swift
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)

指定したところから取るといった感じです。コード見てもらった方が早いかもです!

.swift
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によって発行された最新のアイテムを組み合わせ、この関数の結果に基づいてアイテムを発行します。現在の二つのアイテムの状態を使って判断処理した後にその結果を流したい時に使うようです!

.swift
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先を同じにする。[リンク先サンプルコードあり]

.swift
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にしてるからって今思いました。

.swift
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のアイテムを発行するものに変更するものだと解釈しました。以下コード見比べてもらえたらと思います。

.swift
let source = Observable.of(Observable<Int>.just(1))

source.bind(onNext: { item in
    print(item)
})

//RxSwift.(unknown context at $10ee7d0f8).Just<Swift.Int>
.swift
let source = Observable.of(Observable<Int>.just(1)).switchLatest()

source.bind(onNext: { item in
    print(item)
})

//1

Zip(zip)

イベントを合わせてくれるみたいです!

.swift
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")

あらかじめある部品について

基本の基本

.swift
searchBar.rx.text
.swift
extension Reactive where Base : UISearchBar {
   public var text: RxCocoa.ControlProperty<String?> { get }
}

このことから、部品が一度『searchBar.rx』で 『Reactive』になることが分かる。
『Reactive』でも使う部品によって呼び出されるものが異なることも理解できる。
何が使えるかは以下のようにその都度探すで問題ないと思っています。

スクリーンショット 2020-05-06 15.55.15.png

サンプルみてみる

pod try RxSwiftにてサンプル見れるみたいなので一番はそれをみながらフムフムした方がいいかと思います!

ちなみにもしエラーになったらpod try RxSwift できない!で修正方法書いたので参考にしていただければと思います。

ちなみに見る場所ですが、『RxSwift/RxExample/RxExample/Examples/』の中色々ですね!

もしプロジェクト起動できない場合はここ見て頂くとフムフムってなるかと思います!!

以下記述はそこに書いてあるほんの一例を書いただけです!

部品.rx.[ここは何があるか] と オブザーバブルの作成の仕方がある程度分かると結構使いこなせそうです!!(。・ω・。)!!

.swift
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)
.swift
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)

参考

以下以外のリンクは必要だと思う所に直接書かさせて頂いています。

Observable

14
10
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?