The choice of database technology for our apps has been something of a question for us the last while, where by “last while” we mean since iCloud Core Data was deprecated, which miffed us no end since we’d rather like our apps’ initial releases to Just Work™ across devices for iOS users without jumping through any great hoops or introducing any dependencies on non-Apple services.
So let’s see what’s new in Core Data this year in the iOS 11 release notes! Errr… nothing?
Hmmm. Let’s check out the What’s New In Core Data WWDC 2017 session…
… kinda thin, don’t you think?
Hmmm, hmmm. Sorta looking like it’s time to seriously evaluate other alternatives, it is.
Soooooo, what to do? Well, here is an article that presents an alternative of interest:
I have been using Core Data since iOS 3.0. With few exceptions, it has served entirely as a network cache. Take data from a network response, turn it into a set of objects, save those objects, and update the user interface. Rinse and repeat.
The stack is pretty simple. A set of nested contexts to keep object building off of the main thread, a couple of models that have init(dictionary: NSDictionary), and some find-or-create helpers can get you a long way. The problem is that the apparent simplicity comes with an incredible amount of baggage. Instability, buggy classes, and outdated APIs make building modern apps difficult.
As a community, we have tried to solve these problems by building wrappers around Core Data. These wrappers add their own issues and none of them hide the fact that Core Data was simply not meant to be used like this…
Nodding along here? Yep, us too.
After some research and planning, I landed on a set of features that I wanted in a persistence framework. The list is pretty short:
- My objects must be plain objects. Requiring model objects to extend a certain base class is painful; especially when you cannot see the source for those classes. I want to know that I can create objects however I like, use them wherever I like, and build my own functionality around them without worrying about what sandbox they belong to.
- I should not have to worry about concurrency. Tools like closures, Grand Central Dispatch, and NSOperationQueue make it easy to write code that spans many threads. Unpacking objects on background threads that are later used to update interface elements is a common operation that should be simple and easy to reason about.
- I should not have to write migration code. Frameworks and libraries can and should be smarter than this. Let me describe how I want the database to look. You take care of the rest.
- I should be able to track and respond to atomic changes. Elements in my application should be able to reload themselves if a single object, or a collection of objects changes. Otherwise it may spend too much time updating things that may not need to be updated, which could have a negative impact on the user experience.
Sounds good. Only thing we’d add as a base requirement is “CloudKit sync” to make the cross-device experience seamless.
And the winner was:
I decided to use YapDatabase. It came highly recommended and it offers support for all of my requirements. YapDatabase is, at its core, a key-value store build on top of SQLite. It has a simple API and is incredibly flexible…
You will notice a few things about my model objects right away: they are completely immutable, they have no knowledge of the persistent store, and no magic superclass. These objects can be passed around the application (and across thread boundaries) without requiring knowledge of the database or how these objects are to be handled…
All database operations in YapDatabase are handled through database connections. YapDatabaseConnection has functions for reading from, writing to, and responding to individual changes in the database. It does all of this in a thread safe manner. One less thing to worry about!
OK, flipping down the feature list there, looks like a solid solution to entry level needs, got a track record and is being easily maintained, just that one little extra base requirement…
• Sync. Support for syncing with Apple’s CloudKit is available out of the box. There’s even a fully functioning example project that demonstrates writing a syncing Todo app.
… well, there we go then. Unless some dramatically superior alternative comes to our attention, next data-storing app we ship will use YapDatabase too, farewell Core Data!