MacRuby notes series: taking the pain out of Core Data (part 2)

In Part 1 we addressed the current state of Core Data programming in MacRuby, and discussed some of the problems and challenges facing Rails programmers accustomed to ActiveRecord. Now let’s address some solutions.

First, some necessary terminology.

These are Core Data concepts that you must be familiar with before you’ll be effective at Core Data persistence in MacRuby (or Objective-C, for that matter).

The Managed Object Model (or MOM) keeps track of objects and their relationships. It doesn’t care about actual persistence; you might think of it as just a picture of the data structures, their attributes and their relationships.

In a Core Data-enabled project there is an .xcdatamodeld file.  It contains the model definitions. When you compile your app, this is compiled into a mom file and stored in a folder with a .momd extension. This is how the application knows about the data structures and relationships to use.

The Managed Object Context (or MOC) acts as a bridge between the MOM and the actual persistence mechanism. You can think of the MOC as an in-memory scratch pad. When you fetch objects from a persistent store, you bring temporary copies into the scratch pad where they form an object graph. You can then modify those objects however you like. Unless you actually save those changes, however, the persistent store remains unaltered.

The Persistent Store Coordinator (or PSC) This is the actual persistence mechanism, and is connected to a MOC.  The PSC is analogous to the actual data storage layer, whether it’s SQLite, XML, or whatever. When you fetch objects, the MOC asks the PSC to return those objects that match the fetch request.

An Entity is most basic building block of a Managed Object Model. It’s a description of something you want to store, such as an author or a mailbox.

A Predicate is a general means of specifying queries in Cocoa, i.e. a conditional. A predicate is your WHERE statement. Predicates have their own syntax in Core Data and it isn’t exactly SQL.

A Sort Descriptor is a means of specifying sorting, i.e. your ORDER BY statement.

Putting it all together (or, “just show me how to retrieve data, please!”)

Fair enough, I know you’re impatient. Here’s my simplification of the whole complicated mess.

I employ a singleton class called Datastore to manage data retrieval. I made it a singleton so that I could access a single MOC, MOM, and PSC from anywhere in my application. You can see my current version of Datastore.rb in this Gist and I encourage you to download it and use it in your own applications. There’s no particular magic there, it’s just a tidy way to keep Core Data code organized.

The main thing that my Datastore.rb gives you is single-line object retrieval. Customarily data retrieval in Cocoa is a highly verbose, un-DRY process. Don’t do that. Simply add Datastore.rb to your MacRuby project, and use my find_by_entity_name() method to do the heavy lifting for you.

Usage examples (don’t forget to reference the Predicate Syntax!)

An easy one: “find all Waypoints whose identifier begins with Z”

wpts = find_by_entity_name('Waypoint', withPredicate:"identifier like 'Z*'")

“retrieve waypoints 16801, 16802, 16803”

wpts = find_by_entity_name('Waypoint', withPredicate:"(SELF in %@)", [16801, 16802, 16803])

“retrieve waypoints SEA, PDX and SAN, ordering by identifier”

wpts = find_by_entity_name('Waypoint', withLimit:25, withOrder:"identifier", withPredicate:"(SELF.identifier in %@)", ['SEA','PDX','SAN'])

Now a slightly more verbose query in which we spread out across several lines:

sort_desc = NSSortDescriptor.alloc.initWithKey("identifier", ascending:true) pred = NSPredicate.predicateWithFormat("identifier BEGINSWITH 'Z'", nil) wpts = Datastore.find_by_entity_name('Waypoint', withLimit:25, withOrder:sort_desc, withPredicate:pred)


4 thoughts on “MacRuby notes series: taking the pain out of Core Data (part 2)

  1. What version combination of Macruby/ActiveRecord are you using? I’m having trouble getting them to work together.

  2. Customarily data retrieval in Cocoa is a highly verbose, un-DRY process.

    With Core Data you can create a fully functional app with a complex data model linked to a complex UI without writing a single line of code. You don’t get much dryer than that. 😉

    On MacOS, Core Data can use bindings which employs key-value observing to automatically link up object from the data model to the UI. The object watch each other an update themselves accordingly without having to hand code everything.

    Putting the Core Data stack inside a singleton is okay but its really superfluous. The application object is a singletons and it employes only one app delegate object for run so the standard practice is to just park the Core Data stack in the app delegate and then access it through the application object singleton. By following naming conventions you can create a generic interface for accessing the Core Data stack from anywhere in any app without having to write custom code each time.

    Your single line fetch wrapper is useful but will only work for simple apps with one context on the main thread. In more complex apps, you need the ability to use multiple context simultaneously e.g. updating the data model with a download from the server while the user continues to work in the UI on the front/main thread or you might have document based app in which every document is its own persistent store with its own set of one or more managed object context.

    To make a more generic fetch wrapper method, you should park the method as a class method of the managed object subclass for the entity being fetched. That way, it can be used with multiple managed object context as needed. Of course, a wrapper like that is only useful for the simplest rigid fetches. For more complex fetches or fetches created at runtime, you need more options.

  3. Hmm it appears like your website ate my first comment (it was super
    long) so I guess I’ll just sum it up what I had written and say, I’m thoroughly
    enjoying your blog. I too am an aspiring blog blogger but I’m still new to the
    whole thing. Do you have any suggestions for rookie blog writers?
    I’d definitely appreciate it.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s