5
7

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 1 year has passed since last update.

RxSwiftの基礎についてまとめてみた

Last updated at Posted at 2022-08-28

概要

RxSwiftの基本的な部分について、インターン期間に深く学ぶことができたので自分の知っている範囲でまとめてみたものになります。RxSwift+MVVMでコードを書く際に意識したいことについても少し記載しておきます。

Observableについて

初めに、RxSwiftを書く際によく見かけるObservableについてです。Observableとは、
シーケンス要素を非同期的に受信できるもので、観測可能、イベントを検知できるもの です。
Observableにデータの流れが加わることで、ストリームとして扱われることになります。

Observableが通知するもの

Observableが通知するものには以下の4つがあります。

onNext 通常のイベント通知、値を入れることができる、何回も呼ばれる
onError エラー通知、一回のみ、呼ばれた時点で終了
onCompleted 完了を通知、一回のみ、呼ばれた時点で終了
onSubscribe 購読されたタイミングを拾うことができる

Subscribeについて

subscribeといえば、購読するということが多いと思いますが、具体的にどういう役割があるのか?について説明すると
subscribeを使うことでObservableにイベントを流すことができるようになり、
後ろにonNext, onSuccess, onErrorなどをつけることができます。イメージとしては、
Observableに対してイベントを流すための手続きを行うものです。
実際にコードを書くときは、 ObservableType.subscribe~ のようにして書きます。

ストリームとは?

ストリームというのは、時間順に並んだ進行中のイベントのことです。イメージとしては川の流れと似てます。
スクリーンショット 2022-08-27 18.31.09.png

上の図で、●は何かしらの型の値、✖︎はエラー、縦棒は完了を表しています。このストリームを抽出したり値を計算したりして、別のストリームを作成でき、新しく作成したストリームに対し、イベントを検知し処理を走らせるように設定できます。
(参考: https://fukatsu.tech/rxswift)

色々なObservable

次に、RxSwiftを扱う際によく出てくるObservableについて説明します。

Single

単一の要素 or 単一のエラーを返すObservableです。
この性質によって、APIリクエストメソッドに使われることが多いです(非同期の単一リクエスト)。
現時点でも使われることは多いと思いますが、async,awaitが出てきたことで使うモチベーションは減ってきているみたいです。

 func fetch() -> Single<[Issue]> {
     Single.create { observer in

         let url = URL(string: "https://api.github.com/repos/rails/rails/issues")!
         let task: URLSessionTask = URLSession.shared.dataTask(with: url) { data, response, error in
             guard let data = data else { return }
             do{
                 let result = try JSONDecoder().decode([IssueDTO].self, from: data)
                 observer(.success(
                     result.compactMap {
                         Issue(
                             number: $0.number,
                             title: $0.title,
                             body: $0.body,
                             url: $0.url,
                             user: .init(login: $0.user.login, avatarURL: $0.user.avatarURL),
                             updatedAt: $0.updatedAt
                         )
                     }
                 ))
             }
             catch {
                 observer(.failure(error))
             }
         }
         task.resume()
         return Disposables.create {}
     }
 }

上記のサンプルコードは、APIリクエストを行い、レスポンスをIssue型の配列をSingleで返すというものになっています。
余談ですが、ここのfetchという命名は、もともとrequest()と命名していたのですが、fetchにした方が
通信を行い情報を取ってくるという意味合いが伝わりやすくなるのでrequest()という命名と比較するとfetch()という命名の方が適切です。

DriverとSignal

Driverの特徴として重要なものは以下の3つです。

  1. メインスレッドを保証
  2. errorなし
  3. 過去の値が流れる(線的に、続いているイメージ)

1について、メインスレッド保証というのはUI処理を行う際にはメインスレッドで行わなければならないというルールがあり、そのため、ViewModel内でObservableをDriverに変換し、 Viewに渡すことが多いです。
RxSwift+MVVM設計の観点で、ViewModelの役割はViewに伝えやすい形に変換することだから、他の層でDriverにせず、ViewModel内でDriverに変換します。

また3についてですが、過去の値というのはsubscribeした時点での値のことです。
例えば、パスワードのバリデーション(8文字以上ならokとか)で、前に入力した文字の情報が必要な場合があると思います。こういう場合は過去の値が流れるDriverを使います。
次に Signal についてですが、Driverによく似ていて、違う点は過去の値を保持しないところです。
Signalのイメージとしては点的イメージで、ボタンタップ検知などに使われます。これはボタンタップが過去におこなわれたかどうかは不要である場合が多いからです。DriverとSignalの使い分けは、上記の内容を意識し、実装意図を伝えるためにもできるようにしたいところです。

just

単一の要素を流すことができるオペレータです。使用例としては
以下のように、文字列をViewに表示するために、bindしたい時とかに使います。

     self.title = Driver.just(issue.title)
     self.body = Driver.just(issue.body)
     self.url = Driver.just(issue.url)
     self.updatedAt = Driver.just(issue.updatedAt)

justについて追記(2022/08/31)

上記の用途で使うのはモックに固定値を入れる場合が多く、どちらかと言うとasDriver的に使う場合が多く、
onErrorなどを拾って、エラーで止まらないようにjustで代替値を与える場合に使ったりします。

SubjectとRelay

SubjectとRelayは、イベントの検知も発生も行うことができるクラスです。
次にSubjectとRelayの使い分けについてですが、Subjectはエラーによって処理を分けたいときに使います。
例えば、通信処理、DB処理などでメッセージを出したい場合などです。
また、SubjectはHotなObservableなので、Hotで扱いたい場合はSubject、Coldで使いたい場合はRelayとして扱う、といった用途の違いがあります。
SubjectとRelayの特徴について表にまとめると、次のようになります。
スクリーンショット 2022-08-28 18.25.24.png

BehaviorRelay

ここからはRelayについて、もう少し詳しく見ていきます。BehaviorRelayというのはRelayの一種で、

  • subscribeしたときに、その時点での一番新しい過去の値が取得できる
  • もしも値の変更を検知したら、最新の値を取得し変換される
  • 線的で、過去の値を取得できるのでDriverタイプ

という特徴があります。Behavior~ と名前がついているものはDriverと同じで、過去の値を取得できると理解しておくと覚えやすいです。

PublishRelay

PublishRelayもRelayの一種で、

  • subscribeした時点での過去の値は取得できない
  • 値が変更され、最新の状態が更新されて初めて値の取得ができる
  • 点的で、過去の値を取得できないのでSignalタイプ

という特徴があります。Publish~ と名前がついているものはSignalと同じで、過去の値を取得できないと理解しておくと覚えやすいです。

まとめ

何か間違ってる点などありましたら、ご指摘いただけると幸いです。
最後まで読んでいただき、ありがとうございました。

追記(2022/08/31)

自分の理解が曖昧だった部分について修正しました。本当に申し訳ございません。

5
7
0

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
5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?