【Swift】Cloud FireStoreを使ったサンプルアプリを作ってみる【Firebase】【iOS】

公開日: 2023/4/26 更新日: 2023/3/27

Firebaseでチャットのようなリアルタイム更新が必要なアプリを作るには、Realtime Databaseを使う必要が有ると思っていました。

公式のドキュメントを読んでいると、Cloud FirestoreとRealtime Databaseの比較についての記事がありまして、どちらもリアルタイム更新が実現できると記載がありました。

簡単に調べた限りだと料金プラン的にもFirestoreを使ったほうがコストを抑えることができるようです。


今回はこのCloud Firestoreを使って、リアルタイム更新、データの追加、取得、削除を行うサンプルを作ってみます。

環境

・MacOS Ventura 13.0
・Xcode 14.2
・Swift version 5.7.2

1. 構成、設定等

【Firebase】

プロジェクト名: SampleFirestoreProject

【iOS】

プロジェクト名: SampleFirestore
画面構成:1画面

2. 完成イメージ

①TextFireldから追加した名前と年齢を表示します。年齢に更新があった場合、リアルタイムで年齢の表示に変更が反映されます。

②名前の入力欄

③年齢の入力欄

④追加ボタン → 名前と年齢をデータベースに追加する

⑤更新ボタン → データベースに書き込んだ年齢データを更新する

⑥削除ボタン →  ドキュメントを削除する


3. 準備


3-1. アカウント作成とFirebaseプロジェクトの作成

まずはFirebaseのサイトでアカウントを作成します。Googleアカウントがあれば簡単に作成可能です。

アカウントの作成が完了したら「使ってみる」をクリックします。


続いてコンソソール画面でプロジェクトの追加をクリックします。


Firebaseのプロジェクト名を入力して続行を押します。

FireStoreのみ使用するため、今回はSampleFirestoreとしました。


このあとGoogleアナリティクスの有効化画面が表示されますが使用しないため、チェックを外して続行します。

以上でFIrebase側でのプロジェクトの作成は完了です。


3-2. SDK設定

プロジェクトの作成が完了したら以下のような画面が表示されますのでiOS+をクリックします。


手順に従って進めていきます。

①アプリの登録

AppleのバンドルID: Xcodeから確認します。

・アプリのニックネーム(省略可)
・App Store ID(省略可)


バンドルIDはXcodeのProjectから確認可能です。


②設定ファイルのダウンロード

GoogleSevice-info.plistをダウンロードしてプロジェクト内にコピーします。


Firebase SDKの追加

Firebase SDKをiOSのプロジェクト内に導入します。

今回はCocoaPodsを使用しました。CocoaPodsをインストールしてから以下の作業を行います。

例)
cd /Users/ユーザー名/Documents/Projects/SampleFirestore/SampleFirestore.xcodeproj

〇〇.xcodeprojを削除してプロジェクトのフォルダ直下に移動します。

cd /Users/ユーザー名/Documents/Projects/SampleFirestore

プロジェクトフォルダに移動したら、プロジェクトフォルダ内にpodfileを作成

pod init

podfileを開く

open podfile

pod file内に[FirebaseFirestore]を追加。

pod 'FirebaseFirestore'

ライブラリのインストール

pod install

以上でFirebaseのライブラリ導入が完了しました。

プロジェクトを一旦閉じて白色のファイルから開き直します。

プロジェクトを開いたら問題なくビルドできるか確認します。



初期化コードの追加

AppDelegate.swiftに初期化コードを追加します。

import FirebaseCore
FirebaseApp.configure()

追加する場所はこちらです。

import UIKit
//追加
import FirebaseCore
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
	//追加        
        FirebaseApp.configure()
        return true
    }
}

3-3. データベースの作成

Cloud Firestoreを選択してデータベースを作成します。


動作確認が目的なので、今回は「テストモードで開始する」を選択しました。


その後ロケーションを選択して有効化します。以上でデータベースの作成は完了です。

4. 実装

ここからは先ほど作成したデータベースを使用して実装していきます。

4-1. レイアウト

各種UIの配置と役割

・TextView(グレー背景部分) - データ表示、リアルタイム更新データの確認用
・TextField×2 - 名前と年齢の入力用
・Button×3 - 名前と年齢の(追加)保存、年齢データの更新、データの削除


4-2. 追加

データの追加はsetDataで行います。

データの追加を行う場所(コレクション、ドキュメント)を指定して、データの追加を行います。


指定したドキュメントが存在しない場合は新たに作成されます。

すでに存在する場合はコンテンツが上書きされます。


ViewController内に以下の処理を追加しました。引数には名前と年齢の文字列を指定しています。

コレクションはusers、ドキュメントはuser1、keyはname、ageとしました。

func setUserData(name: String, age: String) {
        db.collection("users").document("user1").setData(["name": name, "age": age]) { err in
            if let err = err {
                print("Error writing document: \(err)")
            } else {
                print("Document successfully written!")
            }
        }
    }

追加ボタンのAction内で名前と年齢をセットしてsetUserDataを実行してみました。

初回のデータ追加、データの全体更新ともに問題なく動作しました。

4-3. 更新

データの一部のみ更新したい場合はupdate()メソッドを使用します。

サンプルとして年齢のみ更新する処理を追加しました。

    //年齢のみ更新
    func updateAge(age: String) {
        let ref = db.collection("users").document("user1")
        
        ref.updateData(["age" : age]) { err in
            if let err = err {
                print("Error updating document: \(err)")
            } else {
                print("Document successfully updated!")
            }
        }
    }

更新ボタンをタップしたタイミングで実行してみます。

    @IBAction func updateButtonAction(_ sender: Any) {
        let age = ageTextField.text ?? ""
        
        updateAge(age: age)
    }

年齢のデータが更新されていることがFirebaseで確認できました。



4-4. 取得

get()を使うことで指定したデータを取得することができます。

users/user1のage、nameを取得して、データをTextViewに表示してみます。


 func getUser1Data() {
        let ref = db.collection("users").document("user1")
        ref.getDocument { document, error in
            if let document = document, document.exists {
                guard let data = document.data() else { return }
                
                guard let name = data["name"] else { return }
                guard let age = data["age"] else { return }
                
                self.textView.text = "名前:\(name) 年齢:\(age)"
               
            } else {
                print("Document does not exist")
            }
        }
    }

user1の名前と年齢が表示されました。

この状態で年齢を22に入力し直して更新ボタンを押してみます。

Firestoreのコンソールでは年齢が更新されていますが、TextViewの年齢はアプリ起動時に一回読み込んだデータなので更新されていないことがわかります。


4-5. リアルタイム更新

リアルタイムの更新を受け取るにはaddSnapshotListenerを使います。

ドキュメントに対してリスナーを設置して、変更があった場合にデータを受け取ります。

変更データを受け取った後にTextViewに反映しています。

func userInfoListener() {
        db.collection("users").document("user1").addSnapshotListener { documentSnapshot, error in
            guard let document = documentSnapshot else {
                print("Error fetching document: \(error!)")
                return
            }
            guard let data = document.data() else {
                print("Document data was empty.")
                return
            }
            print("Current data: \(data)")
            
            guard let name = data["name"] else { return }
            guard let age = data["age"] else { return }
            
            self.textView.text = "名前:\(name) 年齢:\(age)"
        }
    }

4-6. 削除

ドキュメントを削除するにはdelete()を使用します。

コレクション、ドキュメントを指定して削除します。

 func deleteUserData() {
        db.collection("users").document("user1").delete() { err in
            if let err = err {
                print("Error removing document: \(err)")
            } else {
                print("Document successfully removed!")
            }
        }
    }

5. まとめ

いかがでしたでしょうか。

今回はFirestoreで簡単なデータ操作をするアプリを作りました。

公式のドキュメントがとても丁寧なので、迷うことなく目的の機能が実装できました。

エラー処理も含めてとてもシンプルに書くことができました。

FireStoreを初めて扱う方の参考になれば幸いです。