FirebaseStorageの使い方・Singleを使って実装する。

現在、firebaseのstorageを使ってProfile画像を作っています。

主な使い方は、Firebaseのドキュメントを使って知ることができます。

https://firebase.google.com/docs/storage/?hl=ja:title

FirebaseはStorageは、Pathを ` Storage.storage().reference() ` にchildを使って指定します。
 ` child("a").child("b") ` と書くとaの中のbに画像が保存されます。

今回は、UserProfileを保存したいので、pathは ` .child("users").child("profile") ` とします。

 ` let ref = Storage.storage().reference().child("users").child("profile")  ` と変数を持たせれば、画像の取得を楽にすることができます。

## はじめに

CocoaPodsでFirebase/Storageをインストールします。

```bash
use_frameworks!
pod "Firebase"
pod "Firebase/Storage"
```

次にFirebase Storageの設定を修正します。
今はAuthorizeしたユーザーしかファイルの読み書きをできないので、誰でもできるように変更します。

## 画像のアップロード
画像のアップロードは、` setData `と言う関数を用いることで使用することができます。
setDataの引数には、保存したい画像のData型とmetaDataを渡します。
metadataは、以下のURLで確認してください。

[https://firebase.google.com/docs/storage/ios/file-metadata?hl=ja]

基本は、nilで大丈夫です。

以下で、UIImageからData型に直すことができます。
0.3と言う数字は、画質に関する情報なのですが、容量の重い画像だとアップロードに時間がかかるので比較的小さい数字でいい気がします。
 `let imageData = myProfile.jpegData(compressionQuality: 0.3) `

戻り値は、metadataとerrorが帰ってくるので、ハンドリングすれば終わりです。

つい数ヶ月前までは、` metadata?.downloadURL() `で保存先のURLを取得できたのですが現在は使えないようです。

以下がアップロードの処理です。

``` swift
 func uploadUserProfile(imageData: Data) -> Single<Void> {
        let ref = Storage.storage().reference().child("users").child("profile")
        return Single.create { observer in
            ref.putData(imageData, metadata: nil) { metadata, error in
                if let error = error {
                    observer(.error(error))
                    return
                }
                observer(.success(()))
            }
            return Disposables.create()
        }
    }

```

## 画像のダウンロード

ダウンロードには、Data型とURLで取得する２通りの取得方法があります。

### Data型で取得する。

Data型は、getDataで取得することができます。引数に、画像のサイズ ' maxSize 'を書きます。
ドキュメントには、` 1 * 1024 * 1024 `と書いてありました。
そして、引数には ` data ` と ` error `　が帰ってきます。

``` swift
 func downloadUserProfile() -> Single<Data> {
        let ref = Storage.storage().reference().child("users").child("profile")
        return Single.create { observer in
            ref.getData(maxSize: 1 * 1024 * 1024, completion: { data, error in
                if let error = error {
                    observer(.error(error))
                    return
                }
                guard let data = data else {
                    fatalError()
                }
                observer(.success(data))
            })
            return Disposables.create()
        }
    }
```

### URL型で取得する
現在のプロダクトは、Kingfisherで画像をキャッシュしているのでURLで取得しています。
URLかたで受け取るには、downloadURLで取得でき、引数は必要ありません。
引数には ` URL ` と ` error `　が帰ってきます。

``` swift
 func downloadProfileURL() -> Single<URL> {
        let ref = Storage.storage().reference().child("users").child("profile")
        return Single.create { observer in
            ref.downloadURL(completion: { url, error in
                if let error = error {
                    observer(.error(error))
                    return
                }
                guard let url = url else {
                    fatalError()
                }
                observer(.success(url))
            })
            return Disposables.create()
        }
    }
```
Singleを使うと、流れてくる最初の値のみを流しsuucessとerrorを流すため、APIなど ` 成功したら結果を、失敗したらエラー情報を返す場合 ` に便利に使えます。