FirebaseのRealtimeDatabaseでUIImageやStringを扱う

経験が浅く色々間違ってそうなのでコメントで教えてください
また、今回は導入の部分は省略してます。
（[公式](https://firebase.google.com/docs/ios/setup?authuser=0)見た方が早い)

# FirebaseのRealtimeDatabaseとは
2014年にGoogleに買収され、現在Googleのインフラストラクチャ上で構築されているクラウド連携サービスのうちの一つ
FirebaseはiOSだけでなくAndroidやweb系、Unityなどでも利用できるサービスです。
その中の一つであるRealtimeDatabaseはその名の通り非常にリアルタイム性が高いデータベースであり、NoSQLでデータの保管と同期をあらゆるデバイス間で簡単にできます。
これらのデータは全てFirebaseのWebサイトから確認することができ、Web上からデータの変更、追加、消去も可能です。
Firebaseのコンソール画面からアクセスして確認してください。

# 実装
まずはともあれimport

```

import Firebase

```

## 値の追加

```

func addData(text : String){
        // データベースへの参照
        let rootRef = Database.database().reference()

        //値を追加する階層を設定
        var conditionRef = rootRef.child("TestApp/String")

        //値を追加
        conditionRef.setValue(text)
    }

```
この関数でaddData(text : "aaaaa")を実行するとFireBaseのコンソール上ではこのようになります。

![スクリーンショット 2017-09-30 0.31.56.png](https://qiita-image-store.s3.amazonaws.com/0/204184/c7880ad3-bffe-ae50-e03b-2f641c0d1ecf.png)

このように値を追加する階層を設定し、値を追加するだけでデータを登録することができます。

## 値を取得する
```

　　　// データベースへの参照
     let rootRef = Database.database().reference()

     //階層の設定
     let conditionRef = rootRef.child("TestApp/String")

     //取得するイベント
     conditionRef.observeSingleEvent(of: .value, with: { (snapshot) in
            
        if let text = snapshot.value as? String {
            print(text)
        }else{
            print("No Data")
        }

     })

```

conditionRef.observeSingleEventのobserveSingleEventは文字どおりこれを実行した時に1度値を取得するイベント設定になっています。

## データの更新を受け取る

```

　　 // クラウド上で、textに変更があった場合のコールバック処理

    // データベースへの参照
    let rootRef = Database.database().reference()

    //階層設定
    let conditionRef = rootRef.child("TestApp/String/")
    
    //値に変更がないか監視するイベント
    conditionRef.observe(.value) { (snap: DataSnapshot) in

        //ここに処理を書く

    }

```
データ更新を受け取るにはViewDidLoad()などで一度このコードを走らせておいてください。
それ以降は変更があるたびにこの関数が呼ばれるようになります。

## データの消去
```

   // データベースへの参照
   let rootRef = Database.database().reference()

   //階層設定
   let conditionRef = rootRef.child("TestApp/")
            
   //値を消去
   conditionRef.child("String").removeValue()

```

## UIImageの追加
このやり方が最適なのか分からないですが・・・
Firebaseにはストレージ容量とダウンロードに制限があるため（もちろんお金払えば上がりますが）UIImageをそのままupるとかなり圧迫される恐れがあるので圧縮するのをおすすめします。
UIImageを一旦BASE64のStringにしてからFirebaseにあげます。
逆にFirebaseからUIImageを得る時にはBASE64のStringからUIImageにデコードしてます。

``` エンコード.

  //UIImageを縮小圧縮してからデータベースに格納できるStringに変換する
  func Image2String(image:UIImage) -> String? {
        
  //ここは用途によって変更してください
  let maxQualityImageData = UIImageJPEGRepresentation(image.resize(size: CGSize(width: 250, height: 250))!, 0.25)
        
   //画像をNSDataにキャスト
   let data:NSData = maxQualityImageData! as NSData
        
   //BASE64のStringに変換する
   let encodeString:String =
            data.base64EncodedString(options: NSData.Base64EncodingOptions.lineLength64Characters)
        
   return encodeString     
   }

```

↑この関数を使ってUIImageをTestApp/Imageに追加してみる

``` 最初に書いた値の追加とやり方同じ.

   // データベースへの参照
   let rootRef = Database.database().reference()

   //値を追加する階層を設定
   var conditionRef = rootRef.child("TestApp/Image")

   //値を追加
   conditionRef.setValue(Image2String(image:******))


    //ユーザートラッキングを解除した時
    func mapView(_ mapView: MKMapView, didChange mode: MKUserTrackingMode, animated: Bool) {
         selectTrackingBuntton.setImage(UIImage(named: "none.png"), for: .normal)
    }
```

追加できるとこんな感じに

![スクリーンショット 2017-09-30 1.30.34.png](https://qiita-image-store.s3.amazonaws.com/0/204184/68bc65b5-54ad-635f-b96b-a3e00422c777.png)

##UIImageの取得

今度はデータベース上にある画像（BASE64のString)を取得してみる
↓これでStringからUIImageに変換し、その後取得

``` StringからUIImageへ.

   //StringをUIImageに変換する
   func String2Image(imageString:String) -> UIImage?{
        
      //BASE64の文字列をデコードしてNSDataを生成
      let decodeBase64:NSData? =
            NSData(base64Encoded:base64String, options: NSData.Base64DecodingOptions.ignoreUnknownCharacters)
        
      //NSDataの生成が成功していたら
      if let decodeSuccess = decodeBase64 {
            
         //NSDataからUIImageを生成
         let img = UIImage(data: decodeSuccess as Data)

         return img
      }

      return nil    
   }

```

データベースから取得して変換

``` 最初に書いた値の取得とやり方同じ.

   // データベースへの参照
   let rootRef = Database.database().reference()

   //階層の設定
   let conditionRef = rootRef.child("TestApp/")

   //取得するイベント
   conditionRef.observeSingleEvent(of: .value, with: { (snapshot) in

      //適当に
      UserImageView.image = self.String2Image(imageString: ((snapshot.childSnapshot(forPath: "Image").value) as? String)!)

   })

```

#最後に
コンパイル試していないところがあるので正しく動くか怪しいです。
また、ゴリ押しのところもあるのでどうやるのが正しいのかわかりませんがここにメモしておきます。