A Year of Using Realm in iComics
As of today, I’ve now officially been using Realm in my current little side project app, shipping on the App Store for a whole year. To mark this milestone, I thought I’d write a quick piece on what that was like, including why I decided to go with Realm, what it was like converting an existing app to it, and what the resulting feedback from users was like.
The Epic Backstory
Since 2012, I’ve been building a DRM-free comic reader for iOS named iComics. The function of the app is very simple: take a ZIP file full of JPEG images, crunch some numbers, and present the images on-screen in the format of a comic book. The goal of the app is to enable users to read comics from online sources that don’t have their own dedicated app (such as Humble Bundle Books).
With elements like caching pre-processed file information, and saving/restoring the user’s reading progress, a proper data framework was required from the start. Initially, I toyed with the idea of using raw SQLite, but eventually chose instead to use this opportunity to try out Core Data for the first time. A lot of my friends had recommended Core Data to me over SQLite, so I was eager to see what it was like.
I won’t go into the specifics too deeply, but suffice it to say, working with Core Data was…a ‘challenge.’ The learning curve was huge, accessing data between threads was often unreliable, and if an error did occur, due to its very Apple-esque ‘black box model’, it sometimes took hours of trial and error to work out what was actually going wrong.
The straw that broke the camel’s back was in October 2014, when I had put the finishing touches on the update that would introduce iOS 7’s new design language. When I uploaded the build to TestFlight, literally every user reported that the app crashed on launch and woudn’t run. After doing some digging, I discovered that installing the update over the previous version was triggering a Core Data migration, which would reliably fail, and corrupt the database! What an absolute showstopper! I hadn’t noticed this at all during development since I was working off a fresh install, so no migrations were occurring.
So, it was at that point where I said a bunch of naughty words and decided to choose a new data storage framework. I was considering biting the bullet and moving to SQLite, when one of my colleagues pointed me at this ‘Realm’ thing and suggested I give it a try. I remember thinking to myself, ‘What the hell. It’s worth a shot. There’s absolutely no way it could make things worse than Core Data did.’
Literally three hours later, there was no longer any trace of Core Data in my codebase; just Realm.
And it just worked.
Straight away. I remember sitting on my couch in utter shock and disbelief for a few minutes simply repeating, “That was it? Really? No way. I’m missing something. It can’t have been that easy. Impossible. Something’s going to explode in my face down the line.”
But no! One TestFlight build release later, and it was clear from the unanimous response from the testers that Realm had instantly made all of Core Data’s problems go away. It felt like magic.
Converting From Core Data to Realm
To be completely honest, I’d actually heard of Realm a few months before adopting it (possibly right after it was announced!). My colleague had showed me the news article talking about it, and I went as far as to download the sample apps and had a play with it. My impression was, ‘Yeah, that’s definitely cool. But surely it would be a lot of effort to switch over from Core Data.’
With many, MANY custom UIView subclasses, and a large number of third-party libraries, the iComics codebase is around 160,000 lines of code (I’m sure that’s not something to be proud of!). As such, I was very wary that doing anything so fundamental as completely replacing the data layer would take a VERY long time to implement and, given the architecture of the code, maybe even impossible. It was only after Core Data catastrophically failed, to the point where the app was rendered un-shippable, that I was motivated to give Realm a try.
Like I said earlier, converting an app of a relatively non-trivial size from Core Data to Realm took mere hours. While Realm doesn’t technically follow the proper conventions of object-relational mapping (ORM) technologies, its API design is sufficiently similar in that it’s very easy to map out its logic in a way that matches (but doesn’t emulate) Core Data. It was simply a matter of converting my
NSManagedObject subclasses to
RLMObject subclasses, converting any
NSNumber properties to straight-up
NSInteger values, and then changing any portions of the code related to querying/saving to the database to the equivalent Realm statements.
What amazed me the most about Realm, as compared to Core Data, was the sheer lack of code and auxiliary files that were required to achieve the same thing. No
.xcdatamodeld files; the schema is derived from the model classes themselves with no boilerplate initialization code; simply two or three lines of code to configure the default Realm file’s settings.
As a sidenote, deleting all of that boilerplate Core Data code felt good. Really really good.
One Year Later
A whole year later, and Realm really has exceeded my expectations. The number of thread-related data crashes/corruptions has dropped to zero (as far as my analytics have told me!), and many users have written that the app somehow ‘feels’ snappier than the previous Core Data version.
Additionally, as Realm has matured and more features have been added in these past months, I’ve been able to refine its integration in the app. Since originally adding Realm to iComics, additional features have been added:
- Being able to configure the default Realm file (such as its location on disk)
- Accessing Realm files from different processes
- Key-value observing on model properties
- Most recently, null property support
Each and every one of these features have meant I could go back and remove much of the original custom code I’d written to ‘simulate’ these features in my app and now rely directly on that functionality in Realm. This has directly lowered my own technical debt as well as made the app more architecturally sound in the process.
Suffice it to say, there has never been a moment in the past 365 days when I regretted ditching Core Data for Realm.
Where to From Here?
While Realm is working incredibly well for me, I’m acutely aware that my app was originally architected for Core Data, and that Realm was (somewhat awkwardly) ‘shoe‑horned’ into Core Data’s place.
Core Data and Realm work in fundamentally different ways. Core Data tries to be clever about batch-loading and then keeping objects in memory, whereas Realm eschews that in favour of lazy-loading data on cue, but in an ultimately faster way.
As a result of that, a lot of my app has been designed to potentially try and cope with concepts like paging groups of objects, and offloading tonnes of work to background threads when it really isn’t necessary to do so with Realm. As a result, I’m planning to rip out the data-heavy components of my app and rewrite them from scratch; this time with a Realm-centric mindset as the goal. Hopefully this would result in less code required to maintain, and even faster, more efficient operation of the app.
So…yeah. Realm is good. Very good. I’m sold.
When I was looking to jump ship from Core Data, my other options were either raw SQLite or JSON. In hindsight, going with either of those would have been an absolute disaster. SQLite would have required a hilarious amount of additional bridging code (e.g., converting SQL queries into objects) and JSON would have been incredibly inefficient.
Suffice it to say, I definitely feel like I made the right choice with Realm, and I’m looking forward to many more years of integrating it into my apps.