Realm + Codable. Part 2.

Denpazakura
4 min readDec 31, 2017

--

There are two ways of pre-populating a Realm database:

  1. Use Realm browser to enter all the data manually or import it there from .xls or csv.
  2. Parse data from a JSON source once your app is launched.

I gave the second approach a try and it worked, but there were some caveats.

Disclaimer: I am focusing on parsing data into Realm database, but not on basics of the framework itself. If you are unfamiliar with Realm, e.g. don’t know how to install it, I recommend reading the official Realm documentation. Or just read Part 1 of the article.

Tools you need:

  • Xcode 9+
  • Realm browser, available on GitHub and App Store
  • Cocoapods (I try to avoid it, but looks like this is the only way to get the newest Realm version working with an iOS project)

Create a new project in Xcode, for example, an empty iOS app, and install Realm with Cocoapods.

Data set

We’ll start with parsing a simple json structure that represents “Cat” object. Each cat has name, breed and weight properties, and a unique identifier which will be used as a primary key for our database.

Add a new json file and paste this code there:

Decoding cats

The Cat class must list all the properties we want to decode. We can tell Realm which property is to be used as a primary key by overriding primaryKey() function.

Now we have to do some typing to implement the Decodable protocol, as we have to list all the object’s properties in the convenience required init(from decoder: Decoder). Note that, because Cat inherits from Object, Xcode will ask us to add some required initializers, so the final version of the class looks like this:

Yes, the class has 5 initializers. Don't forget to import both Realm and RealmSwift modules.

Data Serializer

Here’s a simple class that will be responsible for parsing:

Now in AppDelegate (or wherever you plan to parse the data), call serialize(input sourceName: String):

Before you run the project, put a breakpoint somewhere in code and print default realm’s location in the console:

Open file using Realm Browser. You should see all the cats from the JSON file there:

We’ve parsed a simple file, but what if your data source is more complex, e.g., has interrelated objects?

Are you a “cat person”?

Let’s upgrade our data by adding a new entity: a cat owner represented by CatPerson class. Create a new JSON file which will contain data about cat owners and their cats — I’ve named it “CatPeople”.

Add a CatPerson class:

How to decode a Realm List

Note the List<Cat> declaration. I didn’t make it optional here because the “cat person” concept sort of assumes there’s no CatPerson without a cat.

How can we parse an array of JSON objects and store it as a list in a realm? Simply decode it as an array and append its content to a list:

The full code:

Next, modify JSONSerializer to work with different JSON sources:

The serializer doesn’t have to know anything about Cat class to store an array of CatPerson objects: a list of cats is decoded just like any other property within the implementation of convenience required init(from decoder: Decoder).

There is another slight code update to make: we’ve already stored all the cats and their primary keys, so if we try to save cats with the same id’s to the database, Realm will throw an error. Therefore, we need to get rid of the old objects before decoding:

An alternative solution would be to delete the default.realm file.

Find the default.realm’s location again and open it. This is what the default.realm should contain:

Now there are 2 cat owners and 5 cats linked to them.

Congratulations, you’ve parsed a JSON file instead of handling everything manually and saved some time! What’s next?

Cats and their humans

John Smith has 3 cats, Jane Doe has 2, and we can use cats property to query data about John’s and Jane’s pets. Is there a way to find cat owner’s data through a Cat object? LinkingObjects is exactly what we need to describe inverse relationships between objects. However, things are getting a bit more complicated (and ugly) here. Add two new properties to the Cat class:

LinkingObjects are not stored by Realm, so, as of now, there’s no way to make a query like this: cat.person.firstname.

Structures in the CatPeople.json do not contain any “owner” field, so it can’t be serialized. That’s why we can make owner property optional and then manually update the owner value with the person value.

Remember that a migration is needed in this case, because we’ve modified the model.

Run the migration and set Realm’s default configuration before trying opening a realm.

Here is how the problem may be handled:

Output: Jane Doe

Thanks for reading and don’t forget to clap!

Recommendations for further reading

Realm Academy

Realm blog

Swift community

--

--