Flapjack: Swift Data Persistence & Core Data
Here on the Mobile Engineering Team at O’Reilly, we try to lean on Apple’s frameworks as much as possible for a number of obvious reasons (documentation, support, reliability, etc). One of those frameworks we’ve used with middling success is Core Data.
It’s a big component, to be sure: part database, part object graph, part cache. It’s fairly easy to get started in an application with it, but use it for any length of time and you might just hit a wall: Core Data has certain rules and complexities that aren’t quite revealed to you until you use it for a while. And over the past few years we’ve grappled with these complexities and developed some concrete processes for handling them.
One of those processes is our own sort of interface we’ve built on top of Core Data. We call it Flapjack, and we’ve open-sourced it and are sharing it with the world. It’s an iOS/macOS/tvOS framework with 2 primary goals:
- Help you abstract your model-focused database persistence layer from the rest of your app
- Simplify the database layer’s API into an easy-to-use, easy-to-remember, full Swift one
It lets you skip the boilerplate commonly associated with Core Data and lets you introduce structured, sane data persistence in your app sooner, letting you spend more of your time creating the app you really want. While it’s been developed against Core Data fairly exclusively, we’ve envisioned it as a database-agnostic layer that could, in theory, be applied to other databases (be it Realm or others).
Getting started
First, check out the README on Flapjack’s GitHub page for instructions on how to get set up. We’ll create a CocoaPod spec for Flapjack once we’ve got better test coverage and added support for a few more things we think it needs (more on that later), but for now, our README has directions on how to include it in your project in its current state. You can also check out the example app included in Flapjack’s git repository to check out how it works.
We wanted Flapjack to make it really easy for us to roll Core Data into a new project without much of the boilerplate, and here’s how to achieve that. In a nutshell, you prep your Core Data stack like so:
It was important to us to leverage Swift generics to create an object fetching and creation API that was expressive, easy to remember, and lowered cognitive overhead. To do so, and to abstract away the underlying data framework a little, we created the DataObject
protocol. For your model objects to take part in the simplified API provided by Flapjack, you’ll need to make sure they conform to DataObject
. For a class such as Pancake
that has the fields identifier
, flavor
, and radius
defined in a Core Data model, this would look like the following.
Now you’re cookin’. Just like Core Data and Realm, Interacting with the data store is context-driven, using references to the DataContext
protocol. Your DataAccess
object is responsible for vending a mainContext
, and then you can query that mainContext
for the objects it tracks using that expressive API mentioned earlier. Check out how simple it is to fetch and create new model objects.
Granted you don’t want to do expensive data operations on the main thread. Flapjack’s Core Data support (again, abstracted behind DataAccess
and DataContext
) follows best practices for such a thing:
Sick of your database? There’s a method for that, too.
Data sources
This wouldn’t be nearly as much fun if Flapjack didn’t provide a way to automatically listen for model changes. The DataSource
and SingleDataSource
protocols define a way to listen for changes on a collection of persisted objects or a single object, respectively. If you’re targeting Core Data, the two implementations of those protocols (CoreDataSource
and CoreSingleDataSource
) are powered by NSFetchResultsController
and listening to .NSManagedObjectContextObjectsDidChange
, respectively.
For a more complete example on how to use CoreDataSource
, see AutomaticViewController.swift
. To see the steps you’d have to go through to access stored data without it, see ManualViewController.swift
.
What’s next?
Flapjack is still very much in its infancy as a framework. It is, however, shipping in production inside our O’Reilly Learning app. We’ve got a laundry list of things we’d like to see implemented in Flapjack. Several of these items are already in the works, but a few of the key items we’re actively working on are:
- More unit tests
- Better documentation (powered by Jazzy and hosted on GitHub pages)
- Lightweight and heavyweight migration API sugar
The best part about making this library open source (apart from sharing our learnings with the world) is that we can get input from the community to build a stronger framework for everyone!
Grab the code here and get started!
Planning on using Flapjack in a project? Let us know! We’d love to find out how our work is shaping the community.