On a recent episode of Fatal Error, the hosts talked about why they’d never use Core Data in a new project. I’m one of those people as well. I’d definitely recommend listening to the episode, but I also thought I’d jot down my reasons for never using Core Data if I have a choice in the matter.
If I had to summarize my problems with Core Data in one word, it’d be this: magic. Core Data does a whole bunch of stuff that for all intents and purposes is black magic. Most of the time you have no idea how anything works. For instance, if you read a property on a model object, you don’t actually know whether it’s in memory, or is being faulted in from disk. Figuring it out is an extremely daunting task (often impossible, since Core Data is not open source), and I don’t know too many people who can actually use Core Data well.
IMO, CoreData’s API is garbage. Here’re the top reasons why.
Model objects need to subclass NSManagedObject
Your model objects need to subclass
NSManagedObject. This means no more value types for model objects. It also means your code is forever tied to Core Data (see point below about isolation).
Everything is mutable
All your model objects are mutable, and can change underneath you in several circumstances. This means you have to reason about concurrency every time you do something as silly as a property read.
Need to pass contexts around everywhere
You basically cannot do anything without a context, so you have to pass contexts around everywhere, effectively making them global. In fact, I recently saw an app which sticks a global context in
AppDelegate, and references it from a whole bunch of places in the app. This effectively makes the app untestable.
Hard to isolate
Good design encourages separation of concerns. Your data layer should not be intricately tied into your presentation layer. Ideally, your data layer should be defined by a protocol, and your presentation layer should simply treat that protocol as a dependency. If implemented this way, I could swap out my data layer from one implementation (say JSON files written to disk), to another (say SQLite), and have no impact on my presentation layer.
With CoreData however, this is virtually impossible, without also losing all the benefits of using CoreData. Swapping CoreData out for another persistence mechanism would require you to effectively re-write most of your app from scratch.
Okay, but I don’t ever want to swap out CoreData for something else. Why should I care? Because separation of concerns is a good idea anyway. It makes testing your app a heck of a lot easier, for one.
Massive learning curve
One of the things I like about Swift, is the idea of progressive disclosure. The idea is that there is a small learning curve to do simple things. As you go along your journey, you will learn more, as you need to. You shouldn’t have to climb a mountain just to get started.
The problem with CoreData, is that you need to learn a ton of stuff to just get started with it. Sure, there are a lot of well written tutorials about it, but the fact is, you shouldn’t need them.
This one is not relevant if you’re only on Apple platforms. However, if you are also on Android, using SQLite on both iOS and Android allows you to not have to re-think a whole bunch of stuff again.
What about Realm?
I haven’t used Realm for anything significant yet. Realm fixes two major problems with CoreData: it is open source 1, and portable.
However, the reason I chose not to delve into Realm too deeply, is that it has several of the problems above as well. Magic, mutability, passing around contexts, etc. I’m also not sure how solid their business model is, so there’s also a risk of the project being abandoned if their company shuts down.
So what do I actually use?
Currently, GRDB. It is a fantastically designed thin, Swifty API around SQLite. It doesn’t try to do too much. It allows you to define model objects the way you want, have them be value types, and have them be immutable. It supports writing SQL just as well as it supports its own SQL generation wrappers.
It does progressive disclosure quite well, IMO. To start with, write your model objects as you usually would, conform to the requisite GRDB protocols, and you’re good to go. If you need to do more, start writing SQL. But, if you don’t understand what WAL is, that’s totally fine - you probably don’t need it. If you do though, it’s right there for you to use.
If you’re writing in Objective-C, FMDB is pretty great.
I’ve also heard good things about YapDatabase, but I haven’t used it myself. Their API seems to be pretty nice, though.
Further reading: a Hacker News comment from Mike Ash on the topic.
Get in touch on twitter @gopalkri if you have any thoughts, comments, feedback, or questions!
Which means that at least in theory, you can go figure out what it’s doing. ↩