A Quick Overview of Basic CoreData Concepts

Somebody asked me today about how to go about creating a Cocoa app which allows Rails-style object-relational mapping. In other words, how do you model a schema in a data store without having to re-model all of it in code? This is exactly what Core Data is designed for.

Core Data Landscape


I think the Core Data Overview tutorial does a pretty good job of laying out the landscape, and I've mentioned some things about Rails and Cocoa before, but it seems like it might be helpful to share a quick cheat sheet reference.

Schema Classes

The Core Data API is effectively split up into schema classes and runtime classes. On the schema side, the NSManagedObjectModel is at the top of the object graph. It contains the complete representation of the schema (though you can have multiple models in your application bundle).

Core Data Model


An NSEntityDescription: Essentially equivalent to a table in a SQL database. A good example of an entity might be a Person, an Image, an Invoice, and so on. An entity contains multiple instances of NSPropertyDescription, which can be one of the following:

  1. NSAttributeDescription: Typically a simple scalar value — string, number, date or simply binary data.

  2. NSRelationshipDescription: A reference to another object in the object graph, such as another Person, Image, Invoice, and so on.

  3. NSFetchedPropertyDescription: A dynamic list of objects that are returned based on a fetch with specific search criteria

Although you can do all of this in code, it's generally easier to design your schema using the Xcode modeler, in which case all of this work is done for you behind the scenes. And Xcode is free, so why not?

Runtime Classes

On the runtime side, the NSManagedObjectContext contains all of your data objects, tracks changes to them, and is responsible for initiating the save process when the user chooses File → Save. You generally want one managed object context per thread.

Core Data Managed Object Context


Every instance of a data object, such as a Person, exists as an instance of NSManagedObject. Each managed object is linked to an NSEntityDescription to describe which property keys it can store data for. When you want to set a value on a managed object, you do something like:
[person setValue:@"Jude" forKey:@"firstName"];

If you define custom accessors on your NSManagedObject subclass, you could also do these sorts of things:
[person setFirstName:@"Jude"];

And with a bit of Objective-C 2.0 fanciness, you can do this:
person.firstName = @"Jude";

Custom accessors are especially helpful for non-object types, such as float, int, and so on (again, this is Objective-C 2.0 syntax):
person.heightInFeet = 6.1;
NSLog(@"person height: %f", person.heightInFeet);


(At WWDC 2007, Session 203 is an introduction to the new features of Objective-C 2.0, and Session 222 dives into more advanced features.)

After the user has made changes to the in-memory data, they will activate a menu item to save the file (or the application might do this periodically itself), which eventually triggers a -save: message in the context. This eventually filters down to the NSPersistentStoreCoordinator, which is responsible for making sure the data is written to the specific store that the objects belong to.

The persistent store coordinator can have multiple active stores (essentially, individual data files on disk) at the same time, and present them to the application as a single store with a single set of objects. This is useful if you have an application which stores a lot of data from multiple sources, and you may want to dynamically load and unload storage locations.

In Tiger, the store API is private, and only supports SQLite, XML and binary. In Leopard, you can create your own store types. This is covered in Session 105 next week, Optimizing Your Core Data Application.

All of these sessions, of course, are listed on the WWDC 2007 session page.
                                            
Compared to Rails

If you are used to working with Rails, Core Data will probably seem like a parallel universe, very similar to your own. Many of the basic concepts are there, though the particular angles you come at things might be a bit different.

In Rails (and Ruby in general), it's accepted and actually encouraged to use language tricks to reduce the total number of lines of code. In Core Data and Cocoa, the idea is to simplify and reduce to the total amount of code (this, after all, what Cocoa Bindings is about) — but it's also important to not get too clever for your own good.

Objective-C gives you a lot of power to do some crazy things. But the first goal is readability, which is not necessarily the same as the fewest lines of code. Remember that other people (including a future version of yourself) will likely want to read this code some day. Creating shortcuts is fine, but culturally, Cocoa discourages the creation of application-specific metalanguages. This is probably partially why there's so little special syntax in Objective-C.

In short, though, a NSManagedObject is essentially equivalent to an ActiveRecord instance. Many of the same rules apply: you get basic behavior for free based on the schema definition, but you can customize the class as well. Leopard supports migrations in Core Data, which will be described in session 111 at WWDC next week.

The other major conceptual difference is the idea of NSManagedObjects being in a state of changed but not saved. This simply comes down to the way a desktop app tends to work versus a web app, and actually caught me off guard initially in Rails.

The context accumulates changes — which can be backed out and redone with with Undo and Redo — but they don't actually end up on disk until -save: is called and the data is passed off to the persistent store coordinator.

Don't Stress

Fortunately, you don't need to memorize all of this to use Core Data. There's a very gentle introduction at Cocoa Dev Central called Build a Core Data Application. It's entirely visual — there's no code to write. You can use that as a starting point and customize with your own code as necessary.
Design Element
A Quick Overview of Basic CoreData Concepts
Posted Jun 9, 2007 — 17 comments below




 

Ross — Jun 09, 07 4269

Great post - and very helpful. Nice to see it will be possible to implement custom stores in Leopard. A lot of interest in Core Animation currently but I think that Core Data with custom stores could be very powerful for devs. That is assuming a store doesn't have to be a database but could be a web-service (for instance).

Franois C. — Jun 09, 07 4274

Thanks for the tips, they're great.

On a side note, the graphics are gorgeous. May I ask what you drew them with?

Scott Stevenson — Jun 09, 07 4277 Scotty the Leopard

On a side note, the graphics are gorgeous. May I ask what you drew them with?
Thanks. Illustrator and Photoshop.

Sam Stigler — Jun 10, 07 4279

Thanks; this is really helpful! I can't wait for custom store types in Leopard; it sounds like it'll be great.

lone — Jun 10, 07 4280

In Leopard, you can create your own store types. This is covered in Session 105 next week, Optimizing Your Core Data Application.

This is great to hear, especially by someone like me that's planning to use Core Data. But it was probably under NDA, wasn't it? :)

Scott Stevenson — Jun 10, 07 4286 Scotty the Leopard

But it was probably under NDA, wasn't it?

The custom store API is mentioned in the description for session 105 on the public site.

Isaac Gouy — Jun 11, 07 4295

the graphics are gorgeous
They are! However as we need to twist diagonally to read them they are also a pain in the neck: as pure eye candy - good, as information - better to show horizontally aligned 2d boxes encapsulating other 2d boxes.

Francois C. — Jun 11, 07 4297

as we need to twist diagonally to read them they are also a pain in the neck

Maybe it's just my weird 3D mental reconstruction, then, but I really don't find it hard to read the pictures. Except maybe the three controllers in the first pic, but that's rather due to the colour contrast with the white and the narrow lettering.

Scott Stevenson — Jun 11, 07 4299 Scotty the Leopard

@Isaac Gouy: good, as information - better to show horizontally aligned 2d boxes encapsulating other 2d boxes

I disagree. I tried to use third dimension is used to differentiate the different items. If all of the items were the exact same height, then I would agree more. I don't think most people should need to physically twist to read anything (the brain tends to spin things for you), but perhaps there's an issue there I'm unfamiliar with.

In any case, the goal isn't just to deliver information, but to make it fun and interesting. I realize some people may disagree with that approach, but I feel that making it fun and interesting can sometimes actually communicate ideas in a way standard diagrams cannot.

Laurent Sansonetti — Jun 11, 07 4313

Speaking of Rails' ActiveRecord, since RubyCocoa 0.11.0 it's now possible to use it instead of CoreData for the design and implementation of a RubyCocoa application backend.

More details here: http://rubycocoa.sourceforge.net/ActiveRecordSupport

Bagelturf — Jun 12, 07 4314

The Core Data API is effectively split up into schema classes and runtime classes. On the schema side, the NSManagedObjectModel is at the top of the object graph. It contains the complete representation of the schema (though you can have multiple models in your application bundle).

I think I see what the big documentation issue is for Core Data. Stated as a problem:

Describe Core Data in terms of the problems it solves. But do so using only terms familiar to and understood by those trying to solve those problems, not using terms familiar to and understood by those who already know alternative solutions.

What is a schema? Why does it exist? What problem does it solve? What's so bad about re-mapping it in code? What is object-relational mapping? Why do I need it? What problem does it solve? Why are there two types of classes used? Why would I want multiple models?

Core Data is hard for those not familiar with typical solutions because they don't understand their problem in terms of the language in use. Increasingly that is the kind of person trying to use it -- someone tackling a problem they are familiar with but using tools with which they are not.

Scott Stevenson — Jun 12, 07 4315 Scotty the Leopard

@Bagelturf: Core Data is hard for those not familiar with typical solutions because they don't understand their problem in terms of the language in use

Terms like "object-relational mapping" and "schema" are common in database programming, along the lines of "class" and "instance variable" in object-oriented programming.

As you say, there are people that aren't familiar with the lingo, but teaching those concepts is much more involved task. Still very important, I agree.

Bagelturf — Jun 12, 07 4322

Terms like "object-relational mapping" and "schema" are common in database programming, along the lines of "class" and "instance variable" in object-oriented programming.

Agreed. But one of the first things out of the mouth of Core Data people is "Core data is not a database" in order to set expectations correctly. Database terminology is being used to explain something that is not a database to a person who is looking for a solution to a problem, not to become a database programmer.

A Core Data introduction aimed at database programmers should dive right in with all the jargon and concepts. That's the fastest route. But this one, like others I see, has a title that aims it at beginners: A Quick Overview of Basic CoreData Concepts. I'm not sure that such a thing is even possible because to be quick it must be brief and so will only make sense to those who already have the concepts understood. And covering only basic Core Data concepts will not be useful to those without the concepts because even if they understand them as a result of the article, the resulting knowledge will be too incomplete to use.

Isaac Gouy — Jun 12, 07 4326

"better to show horizontally aligned 2d boxes encapsulating other 2d boxes"

Scott Stevenson wrote I don't think most people should need to physically twist to read anything (the brain tends to spin things for you), but perhaps there's an issue there I'm unfamiliar with.

Is the brain doing extra work to spin things? Is it harder to read text written at 45 degrees than text that's horizontal? :-)


Scott Stevenson wrote ... I feel that making it fun and interesting can sometimes actually communicate ideas in a way standard diagrams cannot.

Did I say "eye candy already"? :-)

If you're actually interested in how well those diagrams communicate ideas compared to "standard diagrams" (whatever they are),print out copies of both, hand them to people with 5 questions about the relationships between the diagram components and give them a minute to answer the questions.

(Does it mean something different when the text is on the top or on the side of a box?)

Scott Stevenson — Jun 12, 07 4330 Scotty the Leopard

But one of the first things out of the mouth of Core Data people is "Core data is not a database" in order to set expectations correctly
This is an unfortunate side effect of written language, which is that some words collide unintentionally. Core Data is not a database in the literal sense, but many of the concepts are brought across from SQL. The idea is to bring the benefits of a database-style design (versus raw blobs of data) while positioning things in a way that makes sense for desktop apps.

a person who is looking for a solution to a problem, not to become a database programmer
I absolutely understand what you mean. I think of it like this: the user manual that comes with a car teaches you how to use the car, not how to drive. There's room for Honda to provide a driving training course, but that's much more involved.

But this one, like others I see, has a title that aims it at beginners: A Quick Overview of Basic CoreData Concepts
I think this is useful for those who understanding something about data modelling and databases (such as Rails and WebObjects programmers), but are curious what the basic building blocks of the CoreData API hierachy is. I think there are quite a few people that fit this description.

Scott Stevenson — Jun 12, 07 4333 Scotty the Leopard

Is the brain doing extra work to spin things? Is it harder to read text written at 45 degrees than text that's horizontal?
Reading is not always the same thing as understanding. I try to see things as 3D in my head, and I think this is often a better fit for complex systems. Even though it may be "quicker" to read something without depth, I'm not convinced everyone will absorb the concept as completely with more shallow representations. That's just my opinion based on my experiences, though.

Personally, the 2D "stack" block diagrams never really resonated with me. I always felt I wasn't quite getting the intention of dependencies or separation. I'm not saying the Cocoa Dev Centrals diagrams are all things to all people, but they make more sense to me than many 2D conventional diagrams. My general approach is to make things I like and then I'm pleasantly surprised if other people like them too.

Mathieu Tozer — Jul 17, 07 4534

What would be really neat is an Entity diagramming tool for Active record! I managed a rake db:schema:dump on a Core data generated sqlite database - the results were interesting! You get stuff like:

ActiveRecord::Schema.define() do

create_table "ZATTRIBUTE", :id => false, :force => true do |t|
t.column "Z_ENT", :integer
t.column "Z_PK", :integer
t.column "Z_OPT", :integer
t.column "ZPRODUCT", :integer
t.column "ZCREATORUSER", :integer
t.column "ZDATECREATED", :timestamp
t.column "ZATTRIBVALUE", :string, :limit => nil
t.column "ZNAME", :string, :limit => nil
end

...

It doesn't look as though a clean (and easily scriptable) conversion to rails compatible migrations could be made without a lot of fuss. Interestingly Core Data many to many relationships didn't convert into migrations well, as the two variables didn't seem to have a type.

sqlite .dump gives

CREATE TABLE Z_7OWNEDBY ( Z_7OWNEDPRODUCTS, Z_10OWNEDBY);

# Could not dump table "Z_7OWNEDBY" because of following StandardError
# Unknown type '' for column 'Z_7OWNEDPRODUCTS'

(I'm guessing it should be something like CREATE TABLE Z_7OWNEDBY ( Z_7OWNEDPRODUCTS INTEGER, Z_10OWNEDBY INTEGER); )

Initially I tried creating a mysql compatible schema by hand editing the sqlite dump and piping the schema into a mysql db, which worked, but oddly my rails installation (on Leopard) doesn't want to talk to mysql.

At any rate I had dreams for automating the procedure (so as to use the XCode diagramming tool to create my Rails back end schema migration descriptions) but at best I think all I can gain is a hint towards how I should (hand) write my migrations. Was worth a try!

Email me if you have tried this out before or have any clues!




 

Comments Temporarily Disabled

I had to temporarily disable comments due to spam. I'll re-enable them soon.





Copyright © Scott Stevenson 2004-2015