14
12

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 5 years have passed since last update.

「比較して学ぶRxSwift4入門」で基本が理解できた

Last updated at Posted at 2018-11-12

技術書典5で買った比較して学ぶRxSwift4入門読みました!
RxSwiftの基本を自分の言葉を交えつつ書いていきます。

RxSwiftとは

RxSwiftとは Reactive Extensions の概念をswiftでも扱えるにした拡張ライブラリ。
これを導入することによって、リアクティブプログラミングが実現できます。

つまりRxSwiftはswiftでリアクティブプログラミングを実現するために必要なライブラリ

リアクティブプログラミングの概念

リアクティブプログラミングとは「時間とともに変化する値」と「振る舞い」の関係を宣言的に記述するもの

命令型プログラミングと比較して説明します。

a = 2
b = 3
c = a*b
a = 3
print(c)

このときのcの値はなんでしょうか。

命令型プログラミングとして考えた場合答えは6となります。
しかしリアクティブプログラミングの観点でみた結果としては正しくありません。

これは先に書いた通り、命令型プログラミングが命令した通りに実行されるのに対して、リアクティブプログラミングは「時間とともに変化する値」と「振る舞い」の関係を宣言的に記述するもので
「c = ab」は単なる「c = ab」ではなくて「cはabの関係にある」というものになります。
したがって命令型とちがい、c = a
bのあとでb = 3 のようにbの値が変更されると、その度にb*cの再計算がバックグラウンドで再計算されるため、cの値は9となります。

他にもリアクティブプログラミングは、Excelを題材として説明されることもあります。

C1セルにはA1とB1の値を掛けた結果が出力されます。

スクリーンショット 2018-11-03 15.07.31.png

A1のセルの値を変更してみます。

スクリーンショット 2018-11-03 15.07.52.png

A1の値の変更に合わせて、C1が自動で再計算されました。
概念的にはこれがリアクティブプログラミングらしいです。

RxSwiftの基本的な書き方

メソッドを実行し、その結果に対してさらにメソッドを実行するメソッドチェーンで書きます。
試しにRxSwiftでHello Worldを書いてみます。

import RxSwift
import RxCocoa

class HogeViewController: UIViewController {
    private let disposeBag = DisposeBag()

    var viewModel: HogeViewModel!

    override func viewDidLoad() {
      super.viewDidLoad()

      viewModel = HogeViewModel()

      viewModel.helloWorldSubject
        .subscribe(onNext: { [weak self] value in
           print("value = \(value)")
        })
        .disposed(by: disposeBag)

        viewModel.updateItem()
    }
}

class HogeViewModel {

    let helloWorldSubject = PublishSubject<String>()

    func updateItem() {
      helloWorldSubject.onNext("Hello World!")
      helloWorldSubject.onNext("Hello World!!")
      helloWorldSubject.onNext("Hello World!!!")
    }
}



// 結果
value = Hello World! 
value = Hello World!!
value = Hello World!!!

<流れ>
1、helloWorldSubjectというSubjectを定義
2、Subjectを購読(≒監視)
3、値が流れてきたらsubscribeの引数であるonNextのクロージャー内が実行され、print文で値が出力される
4、定義したクラスが破棄されたら購読も自動的に破棄される

Subjectを使った書き方はこのようにViewController/ViewModel間のデータの受け渡しや、遷移元/遷移先のViewController間でのデータの受け渡しでよく使われるようです。

よく使われるクラス・メソッド

####### Observable
直訳で観測可能という意味。
イベントの発生元であり、イベントを検知 するためのもの。
先の例に書いたsubscribeやこの後に書くbindやOperatorはこのObservableに対して実行するメソッド。
<Observableが通知するイベント>
onNext,onError,onCompleted
onNextのイベントが流れてきたらonNextのクロージャ実行、エラーイベントが流れてきたらonErrorのクロージャ実行、完了イベントが流れてきたらonCompletedクロージャを実行します。
onErrorとonCompletedは省略可。

hogeObservable
    subscribe(onNext: {
      print("next")
    }, onError: {
      print("error")
    },onCompleted: {
      print("completed")
    })

######Tips!: ObservableとObserver
Observable → イベント発生元・イベント検知
Observer → 登録されている(イベント)処理。onNextやonError、onCompleted等のクロージャ内で実際に行われる(イベント)処理

hogeObservable // Observable
    subscribe(onNext: {// Observable
      print("next") // Observer
    })

####### Subject、Relay
Observableがイベントを検知するためのクラスだったのに対して
Subject、Relayは自身でイベントを発生させることもできるクラス。
代表的4種類

  • PublishSubject
  • BehaviorSubject
  • PublishRelay
  • BehaviorRelay
スクリーンショット 2018-11-03 20.18.35.png

大まかな使い分け

基本的に、どちらもイベントの検知に加えてイベントの発生もできる。

  • Subject: 通信処理やDB処理等で成功したとき、エラーが発生したとき、完了したときのイベントがながれてくる。その内容によって処理を分岐させる
  • Relay: UIに値をBindする。onErrorやonCompletedが流れてくると購読が止まってしまい、その先のタップイベントや入力イベントを拾えなくなってしまうためonNextのみが流れてくる。

ただコード上RelayはSubjectの薄いラッパーで、onNextでなくaccpetでonNextのイベントを流す。このacceptも内部的にはonNextを読んでいるので特別なことはしていないです。

// SubjectとRelayのonNextイベント流し方

let hogeSubject = PublishSubject<String>()
let hogeRelay = PublishRelay<String>()

hogeSubject.onNext("ほげ")
hogeRelay.accept("ほげ")


// PublishRelayの実装コード一部

public final class PublishRelay<Element>: ObservableType {
    public typealias E = Element

    private let _subject: PublishSubject<Element>
    
    // Accepts `event` and emits it to subscribers
    public func accept(_ event: Element) {
        _subject.onNext(event)
    }

####### bind

一般的にBindは双方向データバインディングだけど、RxSwiftでは単方向データバインディング。
振る舞いはsubscribeとだいたい同じ。
コードで書くと

 nameTextField.rx.text
     .bind(to: nameLabel.rx.text)
     .disposed(by: disposeBag)

となりto以下に流れてきた値を入れる感じ。

これをsubscribeで書くと

 nameTextField.rx.text
     .subscribe(onNext: {[weak self] text in
     self?.nameLabel.text = text
     })
     .disposed(by: disposeBag)

となるため、subscribeとbindはだいたい同じ。

####### Operator
ここまで書いてきたようにobservableから流れてきた値をそのままsubscribeすることはあまりなく、だいたい途中で何かしら値を加工してからsubscribeやbindする場合が多いらしい。
Operatorはその「値を加工」するものです。
OperatorはObservableに対してイベントの値の変換・絞り込み等、加工を施して新たにObservableを生成します。また他にも2つのObservableのイベントを合成・結合もできます。

*どんなOperatorがあるかは長いので割愛

まとめ

Rxを使うことで監視側でイベント検知と、イベント処理を行えるのでcallbackもdelegateもいらないのは便利だなーと月並みの感想。。。
本ではここからさらにcallbackやKVOとの比較を実際にサンプルコードを用いて説明してくれるので、RxSwiftの入門的内容ではあるけれどとてもわかりやすく、この本を読み終えたいま個人的にはRxへのとっつきにくさが解消された感じです。
RxSwiftわからないいいいって人は最初の一冊として選んで読んでみてはどうでしょうか。(サンプルコードは他の記事で書かれてますね。

追記

個人的にわかりやすい他のRxSwift記事
https://qiita.com/_ha1f/items/e16ddc6017c4ad807c3c
https://qiita.com/k5n/items/17f845a75cce6b737d1e
https://qiita.com/takashi9314/items/11d043b5703baa4e1223
https://qiita.com/usamik26/items/2bbd0b8d304ab42b2279
https://qiita.com/KentaKudo/items/d9ff7cdc639c24301456
https://qiita.com/konojunya/items/ee55d791bdd5aa5a30de
https://fukatsu.tech/rxswift
https://qiita.com/syou007/items/41ff1469ee7a92e7ec57
https://qiita.com/nakagawa1017/items/c9a9250607e43495902a
https://qiita.com/orimomo/items/3120aff12a06f0ab14e2#_reference-1f16d6d0888a8f64fb51
https://qiita.com/jollyjoester/items/c4013c60acd453ea7248

14
12
1

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
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?