Realm is an amazing framework which helps developers and companies to build faster and more intuitive databases for mobile applications. At Tellus, I've been working with it for two years and I'll share some bits of my experience.
Common Issues
1. Managed instances of Object are thread-confined, meaning that they can only be used on the thread on which they were created. You cannot have multiple threads sharing the same instances of Realm objects.
Let's walk through it with an Example. First, a pretty simple model of a Property π:
Want to read this story later? Save it in Journal.
My goal is to create a RealmHelper class to write one Object into Realm using multithreading. My first attempt is pretty straightforward but, unfortunately, it crashes. Take a look at the import function:
The crash reason is Terminating app due to uncaught exception 'RLMException', reason: 'Realm accessed from incorrect thread.' and the problem is on the 14th line. I am using one Object from the realmQueue in the main queue. To fix it, I will make use of the ThreadSafeReference object:
It looks good but happens to keep crashing π. The crash description is the same as before, but now the real reason is on the 15th line: we can't share Realm instances across multiple threads either. Let's get a final version of this function:
Great π we built an import function, it doesn't block the main thread and doesn't crash π
. But, before we go to the next topic, there is one more thingβ¦ ThreadSafeReferences are expensive and querying the object by its primary key can be faster π±. Take a look at the final version of this function π. The average run time of the version above was 0.08468s and the average run time of the version below was 0.05470s.
2. You can't update Objects outside of a write operation.
I hope you enjoyed the hardest step of the trip because now we just wanna update a property of one Object!
Of course, it will crash at line 5 with reason: Terminating app due to uncaught exception 'RLMException', reason: 'Attempting to modify object outside of a write transaction β call beginWriteTransaction on an RLMRealm instance first.'
We fixed it in a fancy way, by adding a function in the RealmHeper class and using ThreadSafeReference. It solves our problem with a function that delegates the write operation to the realmQueue, waits for its completion, and returns the updated object.
Its usage:
As I said before, ThreadSafeReferences are expensive and I'm pretty sure you can write a more efficient update function π (and without those ugly forced unwraps β οΈ)
How to manage multiple Realms?
The challenge: seed the local database of a demo account with data from a local file, to provide faster loading time (than a network call). Problem: in our project, the .realm file (the one generated by Realm with your database) was designed to be user-specific.
The solution we adopted was having two .realm files, each of them with a specific Realm.Configuration. It worked like a charm and we just had to update our import functions to receive the Realm initialization block as a parameter (remember, Realm instances can't be shared across threads).
The import signature became something like:
Final thought
Even though making the Object as the project's Model bring advantages in terms of updating/observation/reaction, it brings the headache of managing them across multiple threads. My suggestion is to build a layer and to restrict all Realm Objects and observations into this layer, parsing the objects as Structs or Classes before delivering them to the rest of the code.
Finally, shout out to my friend and colleague Roger Oba, for reviewing this article.
Follow me to read about exponential technologies and software development π
π Save this story in Journal.
π©βπ» Wake up every Sunday morning to the week's most noteworthy stories in Tech waiting in your inbox. Read the Noteworthy in Tech newsletter.