Rapture in Venice

:: Mobile Design and Development Shop specializing in iPhone, iPad, and Android

InnerBand Tutorial Part 2: Core Data Quick and Easy!

This is the second part of a multi-part series on the InnerBand Framework. Previously, in InnerBand Tutorial Part 1: Introduction and Functions, I reviewed what the InnerBand Framework is and the basic mechanics of its macros.

The various Apple frameworks are hit and miss. Some of them, such as UIKit, are spot on in their design and its consistency makes UI development simple and easy. Core Data, the persistence framework of iOS, is sadly not so gifted. The SDK is clumsy, easy to get wrong, and worst of all requires a lot of boilerplate code to manage your data.

Until InnerBand, anyway. :-)

The CoreDataStore is the featured player in InnerBand when it comes to wrapping the CoreData framework. I conceived of this layer after completing my first Core Data-based project. During a post-mortem review, I was disgusted with all of the low-level, hard-to-understand code that was the result. When I write my persistence code, I expect it to be focused on logic and my app’s data structures, not the silliness I was forced to add. Maybe you feel the same way? NSPersistentStoreCoordinators, NSManagedModels, and NSManagedObjectContexts — OH MY!

Let’s see how the CoreDataStore fixes everything.

Initializing and Clearing Core Data

There is only one requirement to use Core Data, and the CoreDataStore, in your project: include the CoreData framework in your project! That’s it. In fact, I recommend not even clicking the “Use Core Data” checkbox when setting up your project. If you do, you’ll want to delete all the Core Data boilerplate that you’ll find in your App Delegate. You won’t need it.

(And by the way, Apple, you shouldn’t be putting that code there…that was a poor choice on your part. Shame. Shame!)

Ready to see how you initialize the CoreDataStore?


Wait, where’s the code? There is none! Once you start using CoreDataStore, it will automatically create your persistence store it if it hasn’t been already. I told you it was going to be easy. :-)

Now, here’s a bonus. Many frameworks don’t make this available, but if you ever wanted to erase all your data so that you can start fresh again, here’s what you do:

[[IBCoreDataStore mainStore] clearAllData];

This is really handy during unit testing when you want to erase any persisted data between tests.

Inserting Data

CoreDataStore supports two styles of API:

  • ActiveRecord Style – This is the preferred API which lets you operate directly on your Core Data objects in the style of the ActiveRecord pattern. It does require you generate your CoreData objects with their entity names. Since this is already common and a best practice, you’ll most likely be using this style.
  • Factory Style – This style doesn’t require generating Core Data objects and requires the client code to specify entity names as an NSString. It works exactly the same, but is less intuitive and prone to errors since it’s not type-checked.

I’ll show both styles. First, we’ll review ActiveRecord Style. You should generate all your Core Data entities as classes being sure the class names match the entity names. This is usually accomplished via XCode, but I highly recommend the mogenerator utility since it uses a better design pattern for generating the classes as two per entity.

Here’s how you create a new object:

Customer *apple = [Customer create];
apple.name = @"Apple";
 
[[IBCoreDataStore mainStore] save];

Here you can see that we create the Customer object directly by calling -create right on it. We save to something called the mainStore. This is an important concept. The mainStore is considered the default NSManagedObjectContext for all operations. For most apps, it’s all you’ll need. It’s essentially using a single database handle for your entire app. One situation where you might want to create your own context is when you want to handle a set of operations that you can rollback at a given time. If you want to perform the same creation with a custom context, the code would look like:

IBCoreDataStore *customStore = [IBCoreDataStore createStore];
 
Customer *apple = [Customer createInStore:customStore];
apple.name = @"Apple";
 
[customStore save];

All of the CoreDataStore methods support this syntax to let you choose a custom CoreDataStore to perform your operations, but the default always is the mainStore. You’ll likely only need this context.

Now, if you’re not generating your objects, you create data another way:

NSManagedObject *apple = [[IBCoreDataStore mainStore] createNewEntityByName:@"Customer"];
apple.name = @"Apple";
 
// always remember to save!
[[IBCoreDataStore mainStore] save];

As you can see, you need to pass the entity name as a string to create the object. Otherwise, the syntax is similar. Note also that you still have the ability to create your own context rather than use the mainStore.

Deleting Data

Deleting data is the same in either style:

[myObj destroy];

Remember, you’ll need to save, too. I won’t show this code anymore, but review the previous section to see how it’s done.

Querying Data

There are many ways to query using CoreDataStore. Here are a series of examples that should be easy to understand. (If they weren’t, InnerBand wouldn’t be doing its job now would it?)

// all methods
NSArray *allCustomers = [Customer all];
NSArray *allCustomers = [Customer allOrderedBy:@"name" ascending:YES];
NSArray *activeCustomers = [Customer allForPredicate:[NSPredicate predicateWithFormat:@"active = 1"]];
NSArray *activeCustomers = [Customer allForPredicate:[NSPredicate predicateWithFormat:@"active = 1"] orderBy:@"name" ascending:YES];

// all methods -- custom data store
NSArray *allCustomers = [Customer allInStore:myDataStore];
NSArray *allCustomers = [Customer allOrderedBy:@"name" ascending:YES inStore:myDataStore];
NSArray *activeCustomers = [Customer allForPredicate:[NSPredicate predicateWithFormat:@"active = 1"] inStore:myDataStore];
NSArray *activeCustomers = [Customer allForPredicate:[NSPredicate predicateWithFormat:@"active = 1"] orderBy:@"name" ascending:YES inStore:myDataStore];

// first methods
UserSettings *settings = [UserSettings first];
Customer *apple = [Customer firstWithKey:@"name" value:@"Apple"];

// first methods -- custom data store
UserSettings *settings = [UserSettings firstInStore:myDataStore];
Customer *apple = [Customer firstWithKey:@"name" value:@"Apple" inStore:myDataStore];

Use whatever you need. There should be no question about what the methods do. The -all methods return all data that matches the query, if there is any. The -first methods simply return the first match. In most situations, you should expect only one result. So, you should be attempting to match singleton data (such as user settings) or a specific match with a unique name.

Summary

The goal of CoreDataStore is to give you access to Core Data without all the ugly boilerplate you’d normally need. I think it does that well, what do you think? In Part 3, I’ll review the Core Data Store, a handy set of methods that make using Core Data much easier!

In Part 3, I’ll introduce the Message Center, a replacement for the NSNotificationCenter that adds the ability to insert code between posting and receiving messages.

Where Do We Go From Here?

In Part 3: The Magical Message Center I’ll review the Message Center and how it makes real-world application flows super simple!

  • Print
  • Facebook
  • Twitter

John Blanco

John Blanco is a freelance iOS and Android developer in Denver, CO. He's been developing mobile apps for 9 years, starting during the medieval days of Java ME, making him the ultimate hipster mobile engineer. Follow him on Twitter!

, , ,

Comments are currently closed.

6 Responses to “InnerBand Tutorial Part 2: Core Data Quick and Easy!”