SwiftUIでFirebase RealTime Databaseを操作する

公開:2021/02/11
更新:2021/02/11
3 min読了の目安(約3500字TECH技術記事

iPhoneアプリ開発初心者です。
Swift UIのサンプルコードが少なかったので、メモ程度に。GitHubにもあとで公開します。

TL;DR;

  • UIApplicationDelegateAdaptorを設定
  • FIRDatabaseReferenceをインスタンス化する

Firebaseの仕組みが知っている場合、iOSの書き方に慣れるだけです。AppDelegate周りの初期化周りだけSwiftUIライクにします。

以下のチュートリアルを参考に書いています。

https://firebase.google.com/docs/database/ios/start?hl=ja

ContentViewとの連携まで書けると親切ですが、自分の場合はそれ以前のところで躓いてしまったので敢えて初歩的な構成にしています。RealTime DatabaseのルールやCocoa Podsでの環境構築などについては言及していません。

UIApplicationDelegateAdaptorを設定

AppDelegateクラス内でFirebaseApp.configure()で初期化する。

struct FirebaseUISampleApp: App {
    @UIApplicationDelegateAdaptor (AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
    
    class AppDelegate: UIResponder, UIApplicationDelegate {
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
            FirebaseApp.configure()
        }
    }
}

FIRDatabaseReferenceをインスタンス化する

サンプルコードまんまです。事前にRealTime DatabaseにJSONを作っておきます。

{
  "posts" : {
    "-MTF5xSihmRIZXoGVG7R" : {
      "Title" : "My first post",
      "author" : "Taro",
      "body" : "Hello, world!",
      "uid" : "001"
    }
  },
  "user-posts" : {
    "001" : {
      "-MTF5xSihmRIZXoGVG7R" : {
        "Title" : "My first post",
        "author" : "Taro",
        "body" : "Hello, world!",
        "uid" : "001"
      }
    }
  },
  "users" : {
    "001" : {
      "username" : "Hanako"
    }
  }
}
    class AppDelegate: UIResponder, UIApplicationDelegate {
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
            FirebaseApp.configure()
            
            var ref: DatabaseReference!
            
            // オフライン機能を有効化
            Database.database().isPersistenceEnabled = true
            
            ref = Database.database().reference()
            
            // 接続状態を表示
            let connectedRef = Database.database().reference(withPath: ".info/connected")
            connectedRef.observe(.value, with: {snapshot in
                if snapshot.value as? Bool ?? false {
                    print("Connected")
                } else {
                    print("Not connected")
                }
            })
            
            let uid = "001"
            
            // usersオブジェクト全体を書き換え
            ref.child("users").child("test").setValue(["username": "aiueo"])
            
            // usernameのみを更新
            ref.child("users/test/username").setValue("abcdefg")

            // 複数のノードを一括更新
            guard let key = ref.child("posts").childByAutoId().key else { return true }
            let post = [
                "uid": uid,
                "author": "Taro",
                "Title": "My first post",
                "body": "Hello, world!"]
            let childUpdates = [
                "/posts/\(key)": post,
                "/user-posts/\(uid)/\(key)": post
            ]
            ref.updateChildValues(childUpdates)
            
            // 完了ブロック
            ref.child("users").child(uid).setValue(["username": "Hanako"]) { (error:Error?, ref:DatabaseReference) in if let error = error {
                    print("データの保存に失敗しました: \(error)")
                } else {
                    print("データは正常に保存されました")
                }
            }

            return true
        }
    }