0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Firebase Realtime Databaseを使った非同期処理の実装 - Swiftのasync/awaitでシンプルに!

Last updated at Posted at 2024-10-16

Firebase Realtime Databaseを使ったデータ保存・読み込み処理を、Swiftのasync/awaitでシンプルに実装する方法を紹介します。

UserProfileの構造

まずはUserProfileの構造体を定義します。

struct UserProfile: Codable, Sendable {
    var nickName: String
    var startDate: Double  // Unixタイムスタンプ(秒単位)
    var follow: [String]

    init(nickName: String = "未設定", follow: [String] = [], startDate: Double = Date().timeIntervalSince1970) {
        self.nickName = nickName
        self.follow = follow
        self.startDate = startDate
    }
}

説明

  • nickName:ユーザー名を保存。
  • startDate:ユーザー開始日をUnixタイムスタンプで保存。
  • follow:フォローしているユーザーのIDリスト。

Firebaseからプロフィールを非同期に取得する

Firebase Realtime DatabaseからUserProfileを取得する関数です。

@MainActor
class ProfilePostModel: ObservableObject {
    var profile: UserProfile = UserProfile()

    // 非同期にFirebaseからプロフィールをロードする関数
    func loadProfileFromDatabase(id: String) async throws -> UserProfile? {
        let ref = Database.database().reference()
        let userRef = ref.child("users").child(id)

        do {
            // Firebaseから非同期でデータを取得
            let snapshot = try await getValueAsync(ref: userRef)
            guard let value = snapshot as? [String: Any] else {
                print("データが存在しないか、フォーマットが不正です")
                return nil
            }

            // 取得したデータをUserProfileにデコード
            let jsonData = try JSONSerialization.data(with: value)
            let profile = try JSONDecoder().decode(UserProfile.self, from: jsonData)

            print("プロフィールのロードに成功しました: \(profile)")
            return profile

        } catch {
            print("プロフィールのロードに失敗しました: \(error.localizedDescription)")
            throw error
        }
    }

    // Firebaseから値を取得する補助関数
    func getValueAsync(ref: DatabaseReference) async throws -> Any? {
        try await withCheckedThrowingContinuation { continuation in
            ref.observeSingleEvent(of: .value, with: { snapshot in
                Task { @MainActor in
                    continuation.resume(returning: snapshot.value)
                }
            }, withCancel: { error in
                continuation.resume(throwing: error)
            })
        }
    }
}

説明

  • loadProfileFromDatabase:指定したidに対応するプロフィールデータを取得し、UserProfileとして返します。
  • getValueAsyncobserveSingleEventasync/awaitでラップして、非同期処理に変換しています。

Firebaseにプロフィールを非同期に保存する

次に、UserProfileをFirebaseに非同期に保存する関数です。

@MainActor
class ProfilePostModel: ObservableObject {
    var profile: UserProfile = UserProfile()

    // 非同期にFirebaseにプロフィールを保存する関数
    func saveProfileToDatabase() async {
        let ref = Database.database().reference()
        do {
            let userRef = ref.child("users").child(profile.nickName)
            let profileData = try JSONEncoder().encode(profile)
            if let profileDictionary = try JSONSerialization.jsonObject(with: profileData) as? [String: Any] {
                try await setValueAsync(ref: userRef, value: profileDictionary)
            } else {
                print("プロフィールデータの変換に失敗しました")
            }
            print("プロフィールを保存しました")
        } catch {
            print("プロフィールの保存に失敗しました: \(error.localizedDescription)")
        }
    }

    // FirebaseのsetValueメソッドをasync/awaitでラップする補助関数
    func setValueAsync(ref: DatabaseReference, value: Any) async throws {
        try await withCheckedThrowingContinuation { continuation in
            ref.setValue(value) { error, _ in
                if let error = error {
                    continuation.resume(throwing: error)
                } else {
                    continuation.resume()
                }
            }
        }
    }
}

説明

  • saveProfileToDatabaseUserProfileFirebase Realtime Databaseに保存します。
  • setValueAsync:FirebaseのsetValueメソッドをasync/awaitでラップし、非同期処理を簡潔に実装します。

まとめ

async/awaitを使うことで、Firebaseとの非同期通信が非常にシンプルになりました。コールバックベースのコードから脱却でき、可読性が高まり、メンテナンスがしやすくなります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?