Introducing Realm: Building Modern Swift Apps with Realm Database

Get started quickly with using Realm in your Swift apps with this free preview chapter from our new book: Realm: Building Modern Swift Apps with Realm Database! By Marin Todorov.

Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Ordinary Code

You’ll find that the class looks very much like a common Swift class. This is one of the greatest things about Realm! You don’t have to go out of your way to adapt your code to work with the persistence layer. You always work with native classes like ToDoItem, while Realm does the heavy-lifting behind the scenes automatically.

To recap: ToDoItem is a class you can persist on disk because it inherits from Realm’s base Object class. The class is pretty much ready to go, so you can start adding the code to read and write to-do items from and to disk.

Reading Objects From Disk

In this section, you’re going to write code to retrieve any persisted ToDoItem objects and display their data in the main scene of your app.

Let’s start off by adding a method to fetch all to-do items from the Realm file on disk. Open Entities/ToDoItem.swift and insert in the extension at the bottom:

static func all(in realm: Realm = try! Realm()) -> Results<ToDoItem> {
  return realm.objects(ToDoItem.self)
    .sorted(byKeyPath: ToDoItem.Property.isCompleted.rawValue)
}

You just added a static all(in:) method which, by default, fetches all to-do items from your default Realm file. Having a realm parameter with a default value allows you to easily work with the default Realm, but also leaves room for using an arbitrary Realm, if needed.

You can actually have more than a single Realm file in your app, as you might want to separate out the data your app uses into different “buckets”. You’ll learn more about this in Chapter 7, “Multiple Realms/Shared Realms”.

Note: You maybe outraged by the use of try! and of course you will have right to be. For brevity’s sake the book code will only focus on Realm’s APIs but if you’d like to learn more about error handling or other Swift related topics do check the “Swift Apprentice” book on raywenderlich.com where we cover Swift itself in great detail.

If you look further down the code, you’ll spot the objects(_) and sorted(byKeyPath:) methods, which are some of the APIs you’re going to use throughout this book. objects(_) fetches objects of a certain type from disk, and sorted(byKeyPath:) sorts them by the value of a given property or key path.

In your code, you ask Realm to return all persisted objects of type ToDoItem and sort them by their isCompleted property. This will sort incomplete items to the start of the list and completed ones to the end. The method returns a Results, a generic results type which gives you dynamic access to the result set.

Next up will be updating your view controller to use this new method to fetch and display the to-do items.

Open Scenes/ToDoListController.swift and spot the items property towards the top of the file. It is an Optional type where you’ll store the result fetched from Realm.

Next, append to viewDidLoad():

items = ToDoItem.all()

This code uses your new all(in:) method to ask Realm for all persisted ToDoItems.

Currently, the app doesn’t display any items when launched, since you don’t have any data stored. You’ll fix that by adding some default to-do items in case the user hasn’t created any.

Creating Some Test Data

Open AppDelegate.swift and add inside the empty initializeRealm() method:

let realm = try! Realm()
guard realm.isEmpty else { return }

You start by getting an instance of the default Realm by initializing it without any arguments. Then, you check if the Realm is empty using the handy isEmpty property. If the Realm isn’t empty, you simply return since there’s no need to add test data.

Don’t worry about the creation of a new Realm in the first line. Initializing a Realm object simply creates a handle to the file on disk. Furthermore, this handle is shared across your app, and returned each time you use Realm() on the same thread. Therefore, you’re not duplicating your data, or consuming any extra memory — all pieces of code in this app work with the same Realm instance and the same file on disk.

Next, add code to create some test data, right after your guard statement:

try! realm.write {
  realm.add(ToDoItem("Buy Milk"))
  realm.add(ToDoItem("Finish Book"))
}

This quick piece of code persists two objects to disk. And by quick, I mean that it’s literally only four lines of code!

You start a write transaction by using realm.write and add two new ToDoItem objects from within the transaction body. To persist objects, you simply create them as you would any other class, and hand them off to Realm.add(_) which adds them to your Realm.

Last but not least, call initializeRealm from application(_:didFinishLaunchingWithOptions:). Just before return true, add the following:

initializeRealm()

Build and run the project to see your new code in action:

That was easier than expected, wasn’t it? To be fair, the starter project did include some code to make your life a tad less complicated, but it’s clear how easy it is to fetch items from disk and persist new ones when needed.

Open Scenes/ToDoListController.swift one more time and look for the UITableViewDataSource implementations in the bottom of the file:

  • tableView(_:numberOfRowsInSection:) uses items?.count to return the number of objects fetched in the items result set.
  • tableView(_:cellForRowAt:) uses an index subscript to get the object at the required index path items?[indexPath.row] and use its properties to configure the cell.

Additionally, the next class extension defines some delegate methods from the UITableViewDelegate protocol that enable swipe-to-delete on table cells. You’ll write the code to actually delete items a bit later in this chapter.

Adding an Item

Next, you’ll add code to allow the user to add new to-do items to their list.

Since this is one of the CRUD operations, let’s add the relevant method to the ToDoItem class. Open Entities/ToDoItem.swift and add right below your all(in:) method:

@discardableResult
static func add(text: String, in realm: Realm = try! Realm()) 
  -> ToDoItem {
  let item = ToDoItem(text)
  try! realm.write {
    realm.add(item)
  }
  return item
}

add(text:in:) lets you create a new ToDoItem instance and persist it to a Realm of your choice. This is a useful shortcut when you don’t intend to use an object outside of the context of the database.

You’re already familiar with the type of code above. You create a new ToDoItem instance, open a write transaction, and use Realm.add(_) to persist the object.

You can now add some UI code to your view controller to let the user input new to-do items and add them to the app’s Realm.

Back in Scenes/ToDoListController.swift, scroll to addItem(), which is a method already connected to the + button in your navigation bar. Add inside addItem():

userInputAlert("Add Todo Item") { text in
  ToDoItem.add(text: text)
}

userInputAlert(_) is a UIViewController extension method (found in the Classes folder of the starter project) that presents a new alert controller on the screen and asks the user to enter some text. Once the user taps OK, you’ll receive the user-provided text in a closure.

In the callback closure, you use the new method you just created to create and persist a new to-do item to disk: ToDoItem.add(text: text).

Run the project one more time and tap on the + button. userInputAlert(_:_:) will display an alert on screen and let you enter the text for a new to-do.

Tapping OK will execute your callback and save the new to-do item to disk.

As you might have noticed, the table view still only displays the two items you fetched when initially loading the view controller.

Use Realm Studio to open the app database default.realm from the Simulator folders and check its contents. For this, you can use the SimPholders tool as mentioned in Chapter 1, “Hello Realm”:

Realm Studio displays a list of all classes stored in your file on the left-hand side and a spreadsheet-like UI on the right side letting you browse all the data persisted in the file:

Hey, that new to-do item has been successfully added – you can find it at the bottom of the list!

In fact, if you re-run the project, you’ll see it appear in your app as well:

It seems like you need a way to refresh the table view whenever the database changes.