TodoAPPでRxSwift入門[part1]


概要

最近RxSwiftを勉強し始めて現在理解していることを備忘録として残せたらいいなと思い記事にします。
そもそもRxSwiftのRxとは

Rx(Reactive X)とは、「オブザーバパターン」「イテレータパターン」「関数型プログラミング」の概念を実装している拡張ライブラリです。
Rxを導入するメリットは、「値の変化を検知できる」「非同期の処理を簡潔に書ける」ということに尽きると思います。 値の変化というのは変数値の変化やUIの変化も含まれます。 例えばボタンをタッチする、という動作もボタンのステータスが変わったと捉えることができRxを使って記述することができます。

とのことです。
詳しくは以下のサイトを参照してください。
入門!RxSwift
RxSwiftについてようやく理解できてきたのでまとめることにした(1)

今回使用するライブラリ

RxSwift pod 'RxSwift'
--- ObservableなどのRx系の本領的なものを使うのに必要
RxCocoa pod 'RxCocoa'
--- UIKitでRxを使うのに必要
RxDataSources pod 'RxDataSources'
--- tableViewなどのdatasourceの扱いを楽にしてくれる
Firestore pod 'Firebase/Firestore'
--- todoの保存をするのに必要

以上のライブラリを使用していきます。

認証機能は?と思われたかもしれないですが今回は省かせていただきます。

また、今回の記事はfirebaseやpodは導入済みのものとして話を進めさせていただきます。

StoreManager

まずはこのアプリのもっとも重要なTodoの追加や取得の処理を書いていきます。
StoreManagerという名前のファイルを作ってください。

StoreManager.swift
import Foundation
import FirebaseFirestore
import RxSwift

class StoreManager {
    static let shared = StoreManager()
    private let store = Firestore.firestore()
}

こんな感じで定義してください。
ここは説明するまでもないと思うので説明を省略します。

次にTodoを保存する関数を作ります。
extensionで拡張すると可読性が上がるので拡張します。

StoreManager.swift
extension StoreManager {
    // firestore にtodoのデータを保存
    func insertTodoToFireStore(title: String, detail: String) {
        let data: [String: Any] = [
            "title": title,
            "detail": detail,
            "createdAt": Timestamp()
        ]
        store.collection("todos").addDocument(data: data)
    }
}

ここも特に説明はいらないと思いますは簡単に説明しておきます。
title,detailを受け取り[String: Any]型のDictionaryにして各値を格納します。そして、todosというコレクション名のコレクションにデータを保存します。

次にデータを取得する関数を作ります。

StoreManager.swift
// firestore からtodosのデータ取得
    func fetchTodosFromFirestore() -> Single<[TodoModel]> {
        Single.create { [weak self](single) -> Disposable in
            self?.store.collection("todos").getDocuments { (snapshots, error) in
                guard let docs = snapshots?.documents, error == nil else {
                    single(.failure(CustomError.error(message: "Failed To Fetch Todos From Firestore")))
                    return
                }
                let todos = docs.map { TodoModel(data: $0.data()) }
                single(.success(todos))
            }

            return Disposables.create()
        }
    }

ここがこのクラスのキモですね。
戻り値にSingle<[TodoModel]>とありますね。
SingleはRxSwiftをインポートしていないと使えないので忘れないでください。
また、現時点ではTodoModelというものが定義されていないのでエラーになると思いますが気になる人はとりあえずTodoModelを定義しておいてください。

Singleについて説明していきます。
SingleはSuccessとErrorを流し、Completedを流さないものになります。
successとはnextを一回だけ流れるものでerrorはそのままですね。
ほーという感じだと思いますがcomplete処理がいらなかったらSingleを使うという感じでいいんじゃないでしょうか。

Singleの他にもMaybe、Completableがあります。
詳しいことは以下の記事を参照してください。
RxSwift 3.3.0で追加された3つのUnit(Single, Maybe, Completable)

次にguard let文の中でエラー処理を書いています。
ここは説明なしでもわかると思います。
そして、取得した値をTodoModelに加工してsuccessで流してあげます。

最後にDisposables.create()ですが、これはストリームのライフサイクルを管理するためのものです。
disposeされたときに、ここに書いた処理が実行されます。
Disposableについて

TodoModel

先ほど飛ばしたTodoModelはこんな感じで書きます。

TodoModel.swift
import Foundation
import FirebaseFirestore

struct TodoModel {
    let title: String
    let detail: String
    let createdAt: Timestamp

    init(data: [String: Any]) {
        title = data["title"] as? String ?? ""
        detail = data["detail"] as? String ?? ""
        createdAt = data["createdAt"] as? Timestamp ?? Timestamp()
    }
}

最後に

part1はここまでになります。
正直まだ理解しきれていないこともあり、調べながらになりますが理解できているところとあまり理解できていないとこがわかってoutputって大切だなと思いました。
また、あまり理解できずに書いてしまっているところや誤解釈してしまっているところがありましたらご指摘の方お願いいたします。

[part2]はViewModelの作成をしていきます。
TodoAPPでRxSwift入門[part2]