Getting Started with Cloud Firestore and SwiftUI
In this tutorial, you’ll learn how to use Firebase Cloud Firestore to add persistence to a SwiftUI iOS application with Swift. By Libranner Santos.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Getting Started with Cloud Firestore and SwiftUI
35 mins
- Getting Started
- Setting Up Firebase
- Setting Up Cloud Firestore
- Architecting the App Using MVVM
- Thinking in Collections and Documents
- Adding New Cards
- Adding the View Model
- Retrieving and Displaying Cards
- Setting Up the Repository
- Setting Up CardListViewModel
- Setting Up CardView
- Setting Up CardListView
- Updating Cards
- Removing Cards
- Securing the Data
- Creating an authentication service
- Using the authentication service
- Adding Authorization Using Security Rules
- Understanding Firestore Pricing
- Where to Go From Here?
Using the authentication service
Open AppDelegate.swift and add the following line after FirebaseApp.configure()
in application(_:didFinishLaunchingWithOptions:)
:
AuthenticationService.signIn()
This code ensures the user is signed in when the app starts.
Next, open CardRepository.swift and add these properties at the top of the class:
// 1
var userId = ""
// 2
private let authenticationService = AuthenticationService()
// 3
private var cancellables: Set<AnyCancellable> = []
This code:
- Declares
userId
, which you’ll use to store the current user id generated by Firebase. - Creates an instance of
AuthenticationService
. - Creates a set of
AnyCancellable
s. This property stores your subscriptions so you can cancel them later.
Next, change init()
to this:
init() {
// 1
authenticationService.$user
.compactMap { user in
user?.uid
}
.assign(to: \.userId, on: self)
.store(in: &cancellables)
// 2
authenticationService.$user
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in
// 3
self?.get()
}
.store(in: &cancellables)
}
Here you:
- Bind
user
‘s id fromAuthenticationService
to the repository’suserId
. It also stores the object incancellables
so it can be canceled later. - This code observes the changes in
user
, usesreceive(on:options:)
to set the thread where the code will execute and then attaches a subscriber usingsink(receiveValue:)
. This guarantees that when you get auser
fromAuthenticationService
, the code in the closure executes in the main thread. - Call
get()
, like in your original initializer.
Change add(_:)
to this:
func add(_ card: Card) {
do {
var newCard = card
newCard.userId = userId
_ = try store.collection(path).addDocument(from: newCard)
} catch {
fatalError("Unable to add card: \(error.localizedDescription).")
}
}
Here, you make a copy of card
and mutate its userId
to the value of the repository’s userId
. Now, every time you create a new card it’ll contain the actual user id generated by Firebase.
Finally, add the following line before .addSnapshotListener(_:)
on get()
:
.whereField("userId", isEqualTo: userId)
This code lets you filter cards by userId
.
Adding Authorization Using Security Rules
Open your Firebase project in your web browser. Then go to Cloud Firestore, and click Rules on the top horizontal navigation bar. You’ll see something similar to this:
This JavaScript-like code is the Firestore Security Rules. These rules define if a user is authorized to access or modify a document. Replace the existing code with this:
// 1
rules_version = '2';
// 2
service cloud.firestore {
// 3
match /databases/{database}/documents {
// 4
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
Here what this does:
- Sets the
rules_version
to'2'
. This is, at the moment, the latest version, and determines how to interpret the following code. - Indicates which service these rules apply to. In this case, Cloud Firestore.
- Specifies rules should match any Cloud Firestore database in the project.
- Specifies only authenticated users can read or write into the document.
These rules determine the authorization part of the app. With authentication, you get to know who the user is. With authorization, you determine what this user can do.
Click Publish to save the changes. Then go back to the project and build and run.
The app won’t display any cards since it’s now filtering by userId
. If you add a new one, it’ll appear. You can even close and re-open the app, and only cards created from now on will appear.
Understanding Firestore Pricing
Understanding Cloud Firestore pricing can save you from spending too much money. Keep the following in mind:
- Cloud Firestore charges you for the number of operations you perform: reads, writes and deletes.
- The pricing varies from one location to another.
- You also have to pay for the storage your database uses and the network bandwidth.
- If you change a single field or a complete document it counts as an operation.
- The number of reads is the number of records returned. So, if your query returns ten documents, you’ll have ten reads. When possible, use
limit
to restrict the number of documents your queries can return. - You can monitor your current budget using Alerts. You can configure it using Google Cloud Console which will also let you check your previous invoices and set your desired daily spending.
- Google Cloud Operation lets you monitor performance and get metrics which can also help your budget plan.
When possible, you should also cache data locally to avoid requesting data from Firestore.
You can find more information in the the Firestore documentation.
Where to Go From Here?
You can download the completed project using the Download Materials button at the top or bottom of the tutorial. Remember, you still have to add your own GoogleService-Info.plist after downloading the final project.
In this tutorial, you learned how to use Cloud Firestore to persist your data and use MVVM to integrate it with your SwiftUI views. You also learned how to implement Anonymous Authentication using Firebase from scratch.
Firebase and Cloud Firestore have much more to offer. If you want to dive deeper into Cloud Firestore, look into the official Cloud Firestore documentation. Or check out Firebase Tutorial: Getting Started, Firebase Tutorial: Real-time Chat or Video Tutorial: Beginning Firebase.
I hope you enjoyed this tutorial. If you have any questions or comments, please join the forum below.