How to Use Codable in Firebase Realtime Database

Learn how to simplify your code for reading and writing data

Mohd Hafiz
Firebase Developers
7 min readOct 26, 2021

--

Photo by Porapak Apichodilok from Pexels

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.

Firebase release note for iOS on Codable support

Getting Started

In this article, we’ll learn how to:

  1. Set up Firebase Realtime Database in an iOS app
  2. Implement theDecodable protocol for reading data from Realtime Database
  3. Save data using the Encodable protocol
  4. Create a simple Todo app using SwiftUI and the Combine Framework
  5. 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.

Adding new project to Firebase

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.

Setup iOS apps in Firebase Project

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.

Enabling Realtime Database service

The next step is to choose the location of your database instance.

Choose database server location

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.

Selecting security rules

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.

Creating new SwiftUI Project in Xcode

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.

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.

Add Firebase iOS SDK Package

In the next screen, choose only these two packages and click the Add Package button.

Choose only FirebaseDatabase and FirebaseDatabaseSwift-Beta

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.

Task.swift Model

View Model

The view model’s role is to enable communication between the views and our Realtime Database instance. Create a new file called TaskViewModelwith 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.

  1. First, we need to import Combine and the Firebase modules for the Realtime Database.
  2. This class is subclassing ObservableObject protocol, which is used to emit important changes to the views.
  3. 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.
  4. The init() function is called when creating the object, which will then call initListener(). The initListener() 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.
  5. The /tasks path contains a list of tasks. So, we need to grab the child objects and cast them into array of DataSnaphot.
  6. tasks will be updated with non-optional Task objects that is filtered in the compactMap closure. The result will be sorted with the latest date and completion status.
  7. This is where decoding happens using the Firebase Swift extension that converts the snapshots into the desired model type.
  8. This is the important part where we pre-defined the model id using childByAutoId() and encode the Task model inside the setValue() function.
  9. The markComplete() function is used to change the task status to complete or incomplete.
  10. 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.

Data in Firebase database to show the object id is similar to 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!

--

--

Mohd Hafiz
Firebase Developers

iOS Developer focusing on Swift — “Read, learn & practice!”.