>_tech-draft
Firebaseのアイコン
Firebase
動画公開日
タイトル

Cloud Firestore CRUD Tutorial: Build a Swift Recipe App

再生時間

10分 44秒

Firebase Cloud FirestoreでSwiftUIクックブックアプリを構築:CRUDとリアルタイム同期

ポイント

  • SwiftUIアプリに永続的なデータ保存機能(クックブック)を実装したい開発者向けの記事です。
  • Firebase Cloud Firestoreを用いたデータモデリングからCRUD操作(作成、読み取り、更新、削除)までを解説。
  • リアルタイム同期に対応したレシピの管理方法を習得し、スケーラブルなアプリ構築に役立てられます。

はじめに:AIレシピアプリに保存機能を

皆さん、こんにちは!Firebaseチームのピーターです。私たちのFriendly Mealサンプルアプリは、AIを使って素晴らしいレシピを生成しますが、お気に入りのレシピを保存したい場合はどうすればよいでしょうか?本日は、Cloud Firestoreを使用して、アプリ内に完全なクックブック機能を構築する方法をご紹介します。レシピの保存、表示、更新、削除まで、一連の操作を学ぶことができます。友達に試してもらったものの、あまり評判が良くなかったレシピを削除したい時にも役立つでしょう。

Cloud Firestoreの最大の利点は、すべてのデータがクラウドに保存されることです。これにより、アプリのユーザーは、調理中に使用するタブレットなど、他のデバイスでも保存したレシピを表示できるようになります。さらに、レシピを友達と共有することも可能です。もしかしたら、これが素晴らしい新しいソーシャルクッキングアプリの始まりになるかもしれませんね。これらすべては、リアルタイム同期を備えたFirebaseの水平スケーリングなドキュメントベースNoSQLデータベースであるCloud Firestoreによって実現されます。

Cloud Firestoreのデータモデリング

データベースにデータを書き込む前に、データの形状を決定する必要があります。ここでは、レシピの主要なプロパティをすべて持つSwiftのstructを定義しています。具体的には、title(タイトル)、description(説明)、cookingTime(調理時間)、ingredients(材料リスト)、そして非常に重要なinstructions(レシピの調理手順)です。これをSwiftUIのリストビューで表示できるようにするため、idプロパティを追加し、IdentifiableおよびHashableプロトコルに準拠させます。

ドキュメントとコレクション

FirebaseはドキュメントベースのNoSQLデータベースです。これは、すべてのデータがドキュメントとして保存されることを意味します。Swiftのstructのすべてのプロパティは、ドキュメントのフィールドにマッピングされます。ドキュメントはコレクション内に保存され、これによりデータをきれいに整理・管理できます。このアプリでは、すべてのレシピをrecipesコレクションに保存します。

ユーザーごとのデータ管理

各ユーザーが自分のレシピのみを表示できるようにするため、レシピドキュメント内にユーザーのIDを保存します。この方法により、アプリ内でユーザーIDによるフィルタリングが可能になります。この動画の終わりには、ユーザーが自分のレシピのみを表示・編集できるようにするためのセキュリティルールの設定方法についてもご紹介します。

SwiftのCodableプロトコルとの連携

Firestoreは、@DocumentIDプロパティラッパーを使用することで、ドキュメントIDをSwift structidプロパティに自動的にマッピングできます。また、SwiftのCodableプロトコルのおかげで、FirestoreはSwift structのすべてのプロパティをドキュメントに、またその逆も自動的にマッピングできます。この機能の詳細や、複雑なデータ型をSwift structからFirestoreへ、そしてFirestoreからSwift structへマッピングする方法については、公式ドキュメントのガイドをご確認ください。

レシピのCRUD操作の実装

データモデルができたので、Firestoreにレシピを保存できます。ここでは、レシピの「作成(Create)」「読み取り(Read)」「更新(Update)」「削除(Delete)」、いわゆるCRUD操作を順に見ていきましょう。

1. レシピの保存(Create)

新しいレシピを保存するには、以下の手順を実行します。

  1. アプリのFirestoreインスタンスへの参照を取得します。
  2. 新しいドキュメントを保存する場所(コレクション)をFirestoreに伝えます。前述の通り、すべてのレシピはrecipesコレクションに保存します。コレクション名を定数として定義しておくと、他のデータベース操作でも使用できるため便利です。
  3. レシピのドキュメントを追加します。Codableプロトコルのサポートにより、これはわずか1行のコードで実現できます(エラーハンドリングを追加する場合は数行増えるかもしれません)。

2. レシピの取得(Read)

データベースへのデータ追加は半分に過ぎません。データの取得も同様に重要です。Firestoreは、データを取得する2つの主要な方法をサポートしています。

  • 一度だけデータを取得する(One-time fetch): getDocumentまたはgetDocumentsを使用します。これは、データを一度だけ読み込む必要がある場合に適しています。
  • リアルタイムで更新を受け取る(Real-time updates): Firestoreには、データを取得し、リアルタイムで更新を受け取る非常に優れた機能があります。これは、ユーザーが複数のデバイスからデータにアクセスしたり、他のユーザーとデータを共有したりするアプリに最適です。

リアルタイム機能を使用するには、リアルタイムで監視したいコレクションまたはクエリごとにFirestoreのスナップショットリスナーを実装する必要があります。このクロージャ内では、まずエラーを処理し、クエリのスナップショットがnilでないことを確認します。スナップショットに含まれるドキュメントをマッピングするコードは、一度限りの取得で示したコードと同じですが、よりエレガントに記述する方法があります。ここではcompactMapを使用してドキュメントを反復処理し、マッピングできなかったドキュメントやnilのドキュメントを除外しています。

3. 既存ドキュメントの更新(Update)

アプリのユーザーは、気に入ったレシピを追跡したいと考えるかもしれません。そこで、ユーザーのお気に入りレシピを追跡する方法が必要です。まず、Swiftのコードベースでレシピタイプに新しいフィールドを追加しましょう。例えば、isFavoriteというOptionalなブール値を加えます。

なぜこのプロパティがOptionalとマークされているのか疑問に思うかもしれません。これは、このフィールドを含まない既存のドキュメントが正しくマッピングされるようにするためです。Firestoreドキュメントに、CodableなSwift structで宣言されたすべてのプロパティが含まれていない場合、マッピングは失敗します。このプロパティをOptionalとマークすることで、FirestoreはOptionalなプロパティをマッピングしようとせずにドキュメントをマッピングします。前述のFirestoreとCodableに関するガイドで、異なるデータ型、Optional、およびプロパティを異なる名前のドキュメントフィールドにマッピングする方法について詳しく説明されていますので、ぜひご確認ください。

この設定が完了すれば、レシピをお気に入りとしてマークするコードを作成できます。例えば、ユーザーがレシピ詳細画面でスターボタンをタップしたときに、Swift structisFavoriteプロパティを切り替えるだけです。次に、このレシピを表すドキュメントへの参照を取得し、最後に、このドキュメント参照に対してsetData(from: updatedRecipe, mergeFields: ["isFavorite"])を呼び出します。Firebase SDKはCodableを使用してレシピをマッピングし、Firestoreドキュメントを更新します。mergeFieldsを指定することで、明示的に言及されたフィールドのみが書き込まれるようにし、その間にユーザーが他のデバイスから変更したかもしれない他のフィールドへの偶発的な変更を防ぐことができます。

4. ドキュメントの削除(Delete)

最後に、ドキュメントの削除を実装しましょう。ここでも、まずドキュメント参照を取得する必要があります。ドキュメントの削除は、deleteメソッドを1回呼び出すだけで完了します。これでお気に入りのレシピでなかったものが跡形もなく消えました。

まとめ:CRUD機能の実装

以上で、レシピに対する完全な作成、読み取り、更新、削除の機能の実装が完了しました。アプリのメイン画面には、以前追加したレシピのリストが表示されています。これらは、実装したスナップショットリスナーを使用してFirestoreから取得されます。リストのスワイプアクションを使用して、レシピをお気に入りとしてマークしたり、削除したりできます。例えば、先日作った「pommy jana」はみんなに好評だったのでお気に入りに追加します。「luxos」は不評だったので削除します。そして、新しいレシピ「cauliflower lentil curry」を生成し、これをクックブックに追加するといった操作が可能になります。

Cloud Firestoreセキュリティルールによるデータ保護

最後に、非常に重要なこととして、Firestoreデータベースのセキュリティルールを必ず設定してください。これにより、アプリの認証済みユーザーのみが自分のデータにアクセスできることを保証します。最低限、サインインしたユーザーが自分のデータのみを読み取り、変更できるようにするセキュリティルールを実装する必要があります。

現在のアプリのデータモデルに対するセキュリティルールは以下の通りです。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /recipes/{recipeId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == resource.data.userId;
      allow create: if request.auth != null;
    }
  }
}

このルールからわかるように、サインインしたユーザーのみが新しいレシピを作成でき、自分のレシピのみを表示、更新、または削除できます。

結論

これで、SwiftのCodableプロトコルを使用してFirestoreにデータを保存する方法、Firestoreスナップショットリスナーを使用してリアルタイム更新をリッスンする方法、そしてわずか数行のコードで既存のドキュメントを更新および削除する方法を習得しました。Firestoreの詳細については、公式ドキュメントをご確認ください。また、データモデリングや高度なトピックの詳細については、「Get to Know Cloud Firestore」ビデオシリーズもぜひご覧ください。

参考動画

Build a complete cookbook feature in your SwiftUI app with Cloud Firestore