Low-level Core Data Tutorial

August 15, 2007

As you all know, simple Core Data applications can be built without much coding thanks to XCode Data Modeler and Interface Builder and, for basic things, you seldom need to deal with Core Data API itself. Nevertheless, a Core Data API does exist that allows you to programmatically define your data model, and in some occasions, it could be appropriate to define a data model programmatically.

A basic introduction to the Core Data API is given in the “Low-Level Core Data Tutorial” from Apple, which guides you through the steps necessary to build a simple command line app that stores a log of all its executions and displays then the log content.

The Low-level Core Data tutorial was partially ported some time ago to RubyCocoa by Ernest Prabhakar. In particular, how to execute a fetch request was not covered, so I decided to take Ernest’s sample a little bit further by implementing that part, left out in the first place. As I was at it, I also polished a little bit the original code, taking advantage of various RubyCocoa enhancements since version 0.4.2, current at the time the original post was written.

Core Data Command Line Client

# Port to Ruby/RubyCocoa of the Low-level CoreData Tutorial
# from Apple.
# Apple Inc. © 2005, 2006 Apple Computer, Inc.
# The RUbyCocoa version is released under the MIT License

require 'osx/cocoa'
OSX.require_framework 'CoreData'

module CoreDataCLI

  #-- constants

  #-- module variables
  @@mom = nil
  @@moc = nil

  #-- functions
  def self.managedObjectModel

    if @@mom
      return @@mom

    @@mom = OSX::NSManagedObjectModel.alloc.init
    runEntity = OSX::NSEntityDescription.alloc.init

    #-- date attribute
    dateAttribute = OSX::NSAttributeDescription.alloc.init

    #-- processID attribute
    idAttribute = OSX::NSAttributeDescription.alloc.init

    #-- Validation Predicate and Warning
    lhs = OSX::NSExpression.expressionForEvaluatedObject
    rhs = OSX::NSExpression.expressionForConstantValue(OSX::NSNumber.numberWithInt(0))
    validationPredicate = OSX::NSComparisonPredicate.objc_send(
          :predicateWithLeftExpression, lhs,
          :rightExpression, rhs,
          :modifier, OSX::NSDirectPredicateModifier,
          :type, OSX::NSGreaterThanOrEqualToComparison,
          :options, nil)

    validationWarning = OSX::NSLocalizedString("Process ID must not be less than 0.",
          "Process ID must not be less than 0.")

          :setValidationPredicates, OSX::NSArray.arrayWithObject(validationPredicate),
          :withValidationWarnings, OSX::NSArray.arrayWithObject(validationWarning))

    runEntity.setProperties(OSX::NSArray.arrayWithObjects(dateAttribute, idAttribute, nil))

    return @@mom

  def self.applicationLogDirectory
    ald = nil
    if (ald != nil)
      return ald

    paths = OSX::NSSearchPathForDirectoriesInDomains(

    if (paths.count == 1)
      ald = paths.to_a[0].to_s + "/Logs/" + LOG_DIR
      fileManager = OSX::NSFileManager.defaultManager
      isDirectory = "NO"
      if fileManager.fileExistsAtPath_isDirectory(ald, isDirectory)
        return ald
      if fileManager.createDirectoryAtPath(ald, :attributes, nil)
        return ald
      ald = nil

  def self.managedObjectContext

    if (@@moc)
      return @@moc

    @@moc = OSX::NSManagedObjectContext.alloc.init

    coordinator = OSX::NSPersistentStoreCoordinator.alloc.initWithManagedObjectModel(managedObjectModel)

    log_file = applicationLogDirectory() + "/" + STORE_FILENAME
    url = OSX::NSURL.fileURLWithPath(log_file)
    print "url=", url, "\n"

# newStore, error = coordinator.addPersistentStoreWithType_configuration_URL_options_error(STORE_TYPE, nil, url, nil, nil)

    newStore, error = coordinator.objc_send(:addPersistentStoreWithType, STORE_TYPE,
          :configuration, nil,
          :URL, url,
          :options, nil,
          :error, error)

    if (newStore == nil)
      OSX::NSLog("Store configuration Failure\n%@", error.localizedDescription)


  class Run 1000) AND (processID < 8580)")

result, err = moc.executeFetchRequest_error(request, err)

 if (result == 0 || err)
   OSX::NSLog("Error while fetching\n%@", err.localizedDescription)
   exit -3

enumerator = result.objectEnumerator
while (run = enumerator.nextObject) != nil
  if (run)
    print "On ", run.date, " as process ID ", run.processID, "\n"


If you copy/paste the code above in a text file, let’s call it coredata_cli.rb for reference, each time you execute it in a shell terminal, it will log the execution date/time and process ID and then list the whole log content. You can play around with the predicateWithFormat argument so to filter the log by process ID or date, if you like. This code has been tested with RubyCocoa 0.11.0.

In comparison to the ObjectiveC implementation, look at how much cleaner is the Ruby code given the absence of memory management (retain/release) and the power of the kvc_wrapper directive provided by the RubyCocoa bridge.

PS: The cdcli.rb file linked from Ernest Prabhakar’s blog is not available anymore at that location. I could retrieve it thanks to the great web WayBack Machine accessible here and you can found the ruby file here.

One Response to “Low-level Core Data Tutorial”

  1. pegolon Says:

    is there a typo in the following line since it doesn’t make sense to me:

    class Run 1000) AND (processID < 8580)”)


Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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

%d bloggers like this: