TodoAPPでRxSwift入門[part1]

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

とのことです。
詳しくは以下のサイトを参照してください。
[入門！RxSwift](https://open8tech.hatenablog.com/entry/2019/04/03/111100)
[RxSwiftについてようやく理解できてきたのでまとめることにした(1)](https://qiita.com/_ha1f/items/e16ddc6017c4ad807c3c)

###今回使用するライブラリ
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`という名前のファイルを作ってください。

```swift:StoreManager.swift
import Foundation
import FirebaseFirestore
import RxSwift

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

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

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

```swift: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`というコレクション名のコレクションにデータを保存します。

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

```swift: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）](https://qiita.com/monoqlo/items/7bcec98432389b3b8909)

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

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

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

```swift: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]](https://qiita.com/apapapa/items/91e3951669165e296880)