Introduction
In this tutorial, I'll show you how to use a powerful yet elegant on-device database solution for your iOS apps: Realm Mobile Database. An alternative to Apple Core Data or SQLite with object-relational mapping (ORM), Realm Mobile Database offers developers an easier and more natural way to store and query data.
What Is Realm Mobile Database?
Billed as a true object database, Realm differentiates itself from other similar libraries by treating data objects as live objects—meaning objects are automatically updated. They react responsively to changes and are easy to persist. Even better, you don’t have the steep learning curve that you would with Core Data or SQLite scripting. Instead, you can work in a truly object-oriented way. Realm Mobile Database has also been open-sourced as of 2016, and is available free of charge to developers.
In addition to Realm Mobile Database, the company also offers Realm Mobile Platform, its flagship PAAS to complement Realm Mobile Database with a server-side solution.
Realm Mobile Platform, extends that core with realtime data synchronization and event handling on the server side, all seamlessly connected to the apps. Developers use the platform to build apps with powerful functionality like messaging, collaboration, and offline-first capabilities. The platform is also ideal for mobilizing existing APIs, making it easy to build highly responsive and engaging apps connected to legacy systems and services. (realm.io)
So Realm Mobile Platform works on the server side in the same seamless way as Realm Mobile Database, providing automatic data synchronization and event handling between the client and server, and in the process abstracting away the complexities that arise when dealing with data synchronization. Realm Mobile Platform is beyond the scope of this tutorial, but I'll come back to it in a future post.
Why Realm Mobile Database?
Beyond saving developers the headache and steep learning curve of Core Data, Realm Mobile Database provides distinctive advantages right out of the box.
Performance & Thread-Safety
Performance-wise, Realm Mobile Database has been proven to run queries and sync objects significantly faster than Core Data, and accessing the data concurrently isn’t a problem. That is, multiple sources can access the same object without the need to manage locks or worry about data inconsistencies.
Encryption
Realm Mobile Database provides its own encryption services to protect databases on disk using AES-256+SHA2 through 64-byte encryption.
This makes it so that all of the data stored on disk is transparently encrypted and decrypted with AES-256 as needed, and verified with a SHA-2 HMAC. The same encryption key must be supplied every time you obtain a Realm instance.
Cross-Platform
Unlike Core Data, Realm Mobile Database is truly cross-platform, supporting iOS, Android, JavaScript web apps, and Xamarin.
Reactive Nature
Because of the way the live objects work, you are able to wire up your UI elements to the data models and your UI will update reactively as the data changes! There is no complicated synchronization code or wiring logic needed, as you would have with Core Data.
When coupled with Realm Mobile Platform and the Realm Object Server, developers will gain the extra benefit of syncing their data to the cloud by simply setting the Realm Object URL.
Even using Realm Mobile Platform, you don’t have to worry about interrupted connections, as Realm has built-in offline capabilities and will queue any data changes to be sent to the server.
Clients
Realm has numerous distinguished clients that have openly adopted Realm Mobile Database, including Netflix and Starbucks.
Alternatives to Realm Mobile Database
Of course, Realm Mobile Database is not the only app storage solution. I already mentioned Apple’s own Core Data, and while it is inherently more complicated to learn, the fact that it belongs to Apple means it will be the de facto database solution for many iOS developers, and will continue to have a large community of developers and support material.
A solution that is somewhat similar to Realm Mobile Database is Google’s Firebase—although this is a combined client-side and server-side solution. Firebase is similarly easy to use and it's free to get started with, but the costs will scale as your usage does. One drawback with Firebase is that you are tightly coupled to their platform, whereas with Realm you are free to use your own back-end—or no back-end at all!
Your First Realm App
Assumed Knowledge
This tutorial assumes you have a working knowledge of Swift, but no Core Data or prior database knowledge is needed.
As well as Realm, we'll be using the following parts of iOS:
- UIKit: to demonstrate our data visually
- CocoaPods: a third-party dependency library that will be used to install Realm Mobile Database
Objectives of This Tutorial
By the end of this tutorial, you will have developed a simple to-do app written in Swift and making use of Realm Mobile Database to persist data locally. You'll get to create a fully functioning Realm-powered to-do app, and along the way you'll learn the following concepts:
- setting up the Realm library on a new project, via CocoaPods
- setting up the App Delegate to import the Realm Library
- creating the ‘live-object’ model objects
- creating the View Controllers and Storyboard in the app UI
- connecting the data model to the view controllers and views
You can download the complete source code from the tutorial GitHub repo.
Set Up the Project
Okay, let’s get started creating our Realm app: RealmDo. We are going to create a new Xcode project, so go ahead and create a Master-Detail application.
Next, if you haven’t installed CocoaPods on your machine, you'll need to do so now. So jump into terminal and type the following:
$ sudo gem install cocoapods
You should then get a confirmation that cocoapods is indeed installed. While you are still in the terminal, navigate to the Xcode project you just created and type the following, to initialize a new Podfile:
$ pod init
You should see a new file named Podfile located in the root directory of your project. This file basically sets out the libraries we want to use in our project. You can refer to the official CocoaPods documentation for more information on how Podfiles work.
Next, we need to add the cocoapod library for Realm, so open up the Podfile in a text editor, and add the following underneath # Pods for RealmDo
:
... use dynamic frameworks use_frameworks! # Pods for RealmDo pod 'RealmSwift' target 'RealmDoTests' do ...
Save the file, exit, and type:pod install
After CocoaPods finishes installing the library, it will ask us to close our Xcode project and open up the workspace. Do that, and we are ready to proceed with coding. We will start with the AppDelegate
.
Set Up the App Delegate to Import the Realm Library
In our AppDelegate
we are going to import the Realm library, so add the following to the AppDelegate.swift file:
import UIKit import RealmSwift @UIApplicationMain class AppDelegate:. ..
Leave the class as is for now, so we can turn our focus to the model object.
Live Object Models
Defining models in Realm is dead simple; you just create a logical model class. In our project, we are going to store reminders, so let's create a class called Reminder.swift, with the following code:
import RealmSwift class Reminder: Object { dynamic var name = "" dynamic var done = false }
For this tutorial, we only need this Reminder
model, so we're all done! It’s that simple, and instantiating a model is just as easy, as we will find out later.
Set Up the View Controllers and Storyboard
Now we focus our attention on the view controllers, but before we go to the MasterViewController.swift class, let's open up Main.storyboard and add a bar button on the top right, called Add, as shown below:
The project was initialized by Xcode with the datasource and delegate wired to the view controller, so all we need to do is add the button we just created to the view controller as an IBOutlet
. Hold and drag from the button to the view controller in split-view mode, to generate the link.
Initializing Realm
Now, moving on to the MasterViewController.swift file, we declare the variables we are going to need, which should look something like the following:
class MasterViewController: UITableViewController { var realm : Realm! //(1) @IBOutlet weak var addButton: UIBarButtonItem! var remindersList: Results<Reminder> { //(2) get { return realm.objects(Reminder.self) } } override func viewDidLoad() { //(3) super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. realm = try! Realm() } …
First, on line (1), we declare the Realm variable which we are going reference to get to our datastore. Then, we lazy-load the remindersList
calling the Realm objects for a list of all Reminder objects. Finally, we instantiate the Realm variable we declared at the start. Nothing too complicated so far!
Set Up the View Delegate and Datasource
Next, we set up our tableView
delegate and datasource methods, as follows:
override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // (4) return remindersList.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) let item = remindersList[indexPath.row] cell.textLabel!.text = item.name // (5) cell.textLabel!.textColor = item.done == false ? UIColor.black : UIColor.lightGray return cell }
On line (4), we get a count of the remindersList
list of objects, which will set the count for the number of rows in our one-section tableView
.
Then, for each cell, we obtain the Reminder
live object’s property to set the label, as well as flagging whether the item is marked as done or not.
Writing Changes to the Database
We want our users to be able to be able to toggle an item as done (and not done), which we indicate by changing the color of the label. We also want to make the table view editable (users will be able to remove cells by swiping from right to left), which we accomplish by adding the following code:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let item = remindersList[indexPath.row] try! self.realm.write({ // (6) item.done = !item.done }) //refresh rows tableView.reloadRows(at: [indexPath], with: .automatic) } override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if (editingStyle == .delete){ let item = remindersList[indexPath.row] try! self.realm.write({ self.realm.delete(item) // (7) }) tableView.deleteRows(at:[indexPath], with: .automatic) } }
On line (6), this is the first time we are writing back to our database, which you simply do within a self.realm.write
block. Note that all you need to do with an instance object is set its value, nothing more. So in this case we toggle the done value by doing item.done = !item.done
.
Line (7) is our second example of writing back to our database: we delete an object from the database by simply deleting the instance object.
Adding New Objects
We are making great progress, and in fact we're almost done! We're now able to load, edit, and delete our reminders, but we are missing one important action: adding a new reminder. To implement this, create a new @IBAction
method, and wire up your storyboard’s Add toolbar button to the method.
We're going to build a simple AlertViewController
in our example, but as a separate exercise, try to refine the app by upgrading this to a new view controller instead.
For now, go ahead and add the following code:
@IBAction func addReminder(_ sender: Any) { let alertVC : UIAlertController = UIAlertController(title: "New Reminder", message: "What do you want to remember?", preferredStyle: .alert) alertVC.addTextField { (UITextField) in } let cancelAction = UIAlertAction.init(title: "Cancel", style: .destructive, handler: nil) alertVC.addAction(cancelAction) //Alert action closure let addAction = UIAlertAction.init(title: "Add", style: .default) { (UIAlertAction) -> Void in let textFieldReminder = (alertVC.textFields?.first)! as UITextField let reminderItem = Reminder() // (8) reminderItem.name = textFieldReminder.text! reminderItem.done = false // We are adding the reminder to our database try! self.realm.write({ self.realm.add(reminderItem) // (9) self.tableView.insertRows(at: [IndexPath.init(row: self.remindersList.count-1, section: 0)], with: .automatic) }) } alertVC.addAction(addAction) present(alertVC, animated: true, completion: nil) }
On line (8), we create a new reminder instance and set its properties. Then, on line (9) we add the reminder via self.realm.add(item)
.
Testing the App
So let’s try out the app, by building and running it in Simulator. Go ahead and add two reminders, and set one of them as done by tapping on it. If you exit your app and open it back up again, your items should still be there.
Realm Browser
And that’s it! With little to no learning curve, and by bypassing any of the complexities of Core Data, we have a fully baked on-device back end. This is Realm Mobile Database. You can also verify that the data is on the device by downloading Realm Browser, a macOS app that allows us to view, debug and edit Realm data objects.
Download the app from the Mac App Store and open the Realm database, which is located in your CoreSimulator/Devices/appID/data/… folder. The file you are looking for is db.realm.
Opening it up, you should be able not just to view your data, but also to edit and add new data. Go ahead and try it!
Conclusion
In this tutorial, you learned about Realm Mobile Database and why it is a powerful tool for the iOS developer. We also briefly touched on its server counterpart, Realm Mobile Platform, which we will cover in a separate tutorial.
We then built a simple reminders app that is powered by Realm Mobile Database. In just a few dozen lines of code, we were able to:
- set up a live-object model for the Reminder
- wire up our view controller to the data model
- declare, instantiate, load, add and delete from the Realm database
Finally, you saw how to use Realm Browser to debug and view your data.
This is has been a very basic introduction to Realm Mobile Database, but you can use it as a starting point for embarking on more advanced topics. As next steps, you could look at:
- The Realm Data Model
- Documentation for Realm for Swift
- Documentation for Realm for Objective-C
- Realm Mobile Database API Reference
Be sure to explore some of the advanced themes in the above documentation, such as working with data relationships, testing Realm objects, threading, and encryption.
And while you're here, be sure to check out some of our other posts on iOS app development!
- Mobile DevelopmentBack-End as a Service for Mobile Apps
- SwiftQuick Tip: Enumerations in Swift
- App Templates15 Best Swift App Templates
- Core DataCore Data and Swift: Core Data Stack