How to Use Codable in Firebase Realtime Database
Learn how to simplify your code for reading and writing data
Using Firebase Realtime Database is one of the quickest and reliable solutions to build our app with backend storage. It is a NoSQL cloud database that provides various features, including real-time sync and offline support.
Firebase offers cross-platform SDKs, allowing us to easily integrate it into our iOS apps. In June of this year, Firebase launched a beta release of Swift Extensions to support Codable for Realtime Database, known as FirebaseDatabaseSwift-Beta.
Getting Started
In this article, we’ll learn how to:
- Set up Firebase Realtime Database in an iOS app
- Implement the
Decodable
protocol for reading data from Realtime Database - Save data using the
Encodable
protocol - Create a simple Todo app using SwiftUI and the Combine Framework
- Perform CRUD operations on the database
Firebase Setup
1. Creating a New Firebase Project
In a browser, open the Firebase Console and add a new project. Then complete the project setup.
Let’s enter TodoApp as our project name and click Continue.
For the next step, just click continue to enable Google Analytics.
2. Adding iOS Platform
Click the Add app button and select the iOS icon to add a new app. Enter the bundle ID that will be used in our Xcode project as shown in the image below. In this case, I entered com.example.RTDBCodable
.
Then, click the Register app button and in the next step, download the .plist
configuration file.
3. Setting up Realtime Database
In the Firebase Console, select Realtime Database at the left pane and click Create Database button to enable the service.
The next step is to choose the location of your database instance.
For the security rules, choose Test mode to enable quick access without need of authentication. You should implement proper security rules and authentication as soon as possible, please refer to the Firebase documentation for more details.
Great. We’ve just finished configuring our Firebase project in the console!
Setting Up iOS Project
1. Creating a New SwiftUI Project
Open Xcode and create new SwiftUI project. Please note that in this tutorial, I am using Xcode 13.0 and iOS 14.
Make sure to use the same Bundle Identifier as you entered in the Firebase project configuration. Click Next to finish the setup.
2. Adding the Realtime Database SPM package
In this section, we will add two main packages for Realtime Database.
- FirebaseDatabase
- FirebaseDatabaseSwift-Beta (contains
Codable
Extension)
In Xcode’s main menu, select File
> Add Packages
and enter the URL below at the right top field.
https://github.com/firebase/firebase-ios-sdk/
To get the latest available package, which is version 8.8.0, make sure we keep the range of the version from 8.0.0 and above in the version field as shown in image below. Then, click Add Package button to proceed.
In the next screen, choose only these two packages and click the Add Package button.
Time for some coding!
3. Initializing Firebase
First, drag the GoogleService-Info.plist
file that we have downloaded before into our project.
Then, update our App file RTDBCodableApp
like this to initialise Firebase.
Model
In this Todo App, we will create only a model called Task
with Codable
protocol. The model will be used in views as well as other places.
View Model
The view model’s role is to enable communication between the views and our Realtime Database instance. Create a new file called TaskViewModel
with ObservableObject
protocol. ObservableObject is a part of Apple’s Combine Framework that is used to emit important changes to the views.
Below is a detailed explanation on the code added above.
- First, we need to import Combine and the Firebase modules for the Realtime Database.
- This class is subclassing
ObservableObject
protocol, which is used to emit important changes to the views. tasks
is marked using the@Published
wrapper. It will enable the subscribers (views) to receive updates when its value updated.dbPath
is the main path for our Todo data.- The
init()
function is called when creating the object, which will then callinitListener()
. TheinitListener()
calls a Firebase function to observe the/tasks
path in our Realtime Database and receive any changes occurred. Whenever the database is updated, it will immediately inform every view that is subscribed to this view model. - The
/tasks
path contains a list of tasks. So, we need to grab the child objects and cast them into array ofDataSnaphot
. tasks
will be updated with non-optionalTask
objects that is filtered in thecompactMap
closure. The result will be sorted with the latest date and completion status.- This is where decoding happens using the Firebase Swift extension that converts the snapshots into the desired model type.
- This is the important part where we pre-defined the model id using
childByAutoId()
and encode theTask
model inside thesetValue()
function. - The
markComplete()
function is used to change the task status to complete or incomplete. - We just need to set the object value to
nil
to remove the object from list.
Important Note
In the step 8, the object is using pre-defined id by calling Firebase childByAutoId()
function. This is very useful to keep the object id generated in the database having the same id used in the model. So, we can easily update the object in database using the /task
path with the same object id.
See the below result in Firebase console, where the generated object id is similar to the Task model id.
As a result, in the markComplete()
and remove()
functions, we can simply use tasks/{id}
path to update the object, where id
refers to the id
of the Task
model.
Views
Below image shows the UI of our Todo app, which contains a navigation bar, simple adding form (at the top), and a task list.
1. AddTaskView
First, let’s add the AddTaskView
, a view which is located at the top of the list with a TextField
and Button
to add new items into our database.
2. TaskRowView
Then, add a TaskRowView
to show the item of each task inside the List
. Each row is clickable to toggle the complete or incomplete status. It is also swipeable to perform delete operation.
3. HomeView
To show the list view, create a new Swift View called HomeView
and add the below code.
In the ForEach
view, we will pass tasks
array from the view model as a dynamic data fetched from Firebase Realtime database. We don’t have to write extra functions to keep the data up-to-date, the view will automatically reload itself once it receives update from the view model.
4. Updating ContentView
Now, update the ContentView
to include HomeView
.
5. Updating App File
Finally, let’s update our RTDBCodableApp
file to add TaskViewModel
as environment object using environmentObject()
modifiers.
EnvironmentObject
In all of our views (HomeView
, TaskRowView
and AddTaskView
), we need to use @EnvironmentObject
wrapper in order to observe any changes in the TaskViewModel. EnvironmentObject is a powerful feature in SwiftUI to propagate an ObservableObject
through the environment.
To make the EnvironmentObject
available to be used in a ContentView and its subviews, we need to pass an instance of TaskViewModel
object using environmentObject()
.
Project Completed
Congratulations! Now, we have completely done all the steps and the project is ready to run. The complete source code can be downloaded from my GitHub repository.
Thanks for reading. Happy coding!