Firebase の Realtime Database を使ってみる。Swift版

## Realtime Database

FirebaseのNoSQL JSON データベースです。リアルタイムとオフラインの両方をサポートしています。
クラウド上のデータを変更すると、リアルタイムにオブザーブしているすべてのクライアントにイベントが通知されます。(コールバックで書けます。)オフラインの場合は、ローカルのキャッシュやパーシステントDBに保存します。

このページはFirebase社のDavidさんのビデオに基づいてます。
https://www.youtube.com/watch?v=joVi3thZOqc
https://www.youtube.com/watch?v=cYinms8LurA

## Firebase

Podでプロジェクトを作成するまではkoogawaさんの[ページ](http://qiita.com/koogawa/items/ca8cce019b4ff7ce2576)をご覧ください。

`pod init`

```swift:Podfile
  pod 'Firebase'
  pod 'Firebase/Database'
```

`pod install`

workspaceを開きます。

`AppDelegate`を以下のように修正します。

```swift:AppDelegate.swift
import UIKit
import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        FIRApp.configure() // この行を追加

        return true
    }
```

`ViewController`を以下のように修正します。

```swift:ViewController.swift
import UIKit
import Firebase

class ViewController: UIViewController {
    // データベースへの参照
    let rootRef = FIRDatabase.database().reference()
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // 子ノード condition への参照
        let conditionRef = rootRef.child("condition")
        // クラウド上で、ノード condition に変更があった場合のコールバック処理
        conditionRef.observe(.value) { (snap: FIRDataSnapshot) in
            print("ノードの値が変わりました！: \((snap.value as AnyObject).description)")
        }
    }
}
```

Firebaseコンソールから、`Database`を開きます。

![Screen Shot 2016-05-22 at 7.59.28 PM.png](https://qiita-image-store.s3.amazonaws.com/0/75231/243bb3a7-eb6c-295c-446e-0b4351445a9d.png)

`+`アイコンをクリックし、ノード `condition` を追加します。値も適当に設定します。(Sunny)

![Screen Shot 2016-05-22 at 8.00.06 PM.png](https://qiita-image-store.s3.amazonaws.com/0/75231/ba85f255-4e6d-eea6-ffcf-c6c7154528e1.png)

ルールタブを開きます。アクセス権限を`true`に変更し、誰でも読み書きできるようにします。

![Screen Shot 2016-05-22 at 8.03.20 PM.png](https://qiita-image-store.s3.amazonaws.com/0/75231/7b53ff31-91dc-0925-32c5-ef4c03e2bab6.png)

Xcodeで、アプリを実行します。

Firebaseコンソールから、`condition`の値を適当に変更してください。(Rain)

![Screen Shot 2016-05-22 at 8.24.51 PM.png](https://qiita-image-store.s3.amazonaws.com/0/75231/ab4db1e2-fdfd-99f9-ed54-7c94860b2fef.png)

Xcodeのコンソールに、変更が出力されます。

```bash
ノードの値が変わりました！: Optional("Optional(Snow)")
```

次に、プログラムからデータベースの値を更新します。

適当にボタンを配置して、アクションを下記のように実装します。

```swift:ViewController.swift
    @IBAction func theButton(sender: UIButton) {
        let conditionRef = rootRef.child("condition")
        conditionRef.setValue("Snow")
    }
```

ボタンを押すと、リアルタイムにサーバの値が変わり、その結果、先ほどのコールバックが呼ばれて、Xcodeのコンソールにログが出力されます。

### 追記
Xcode8で、
`Failed to fetch default token Error Domain=com.firebase.iid Code=6`
が出る場合、`TARGETS > Keychain Sharing` を `ON` にします。

一覧を初期表示とかで、一回だけ取得したい時、`observeSingleEvent`でごそっとデータを持ってこれる。子ノードで絞りたいときは、rootRef.child('coutries').child('cities')

```swift
rootRef.observeSingleEvent(of: .value, with: { (snapshot) in
    // Get user value
    let value = snapshot.value as? NSDictionary
    print("value \(value)")
```