Starting in 1996, Alexa Internet has been donating their crawl data to the Internet Archive. Flowing in every day, these data are added to the Wayback Machine after an embargo period.
Cocoa has been refined dramatically over the
years, but no one technology has brought such sweeping advances as Core
Data. Using the Core Data framework, you can create a suprisingly
sophisticated application before you write your first line of code.
Your first thought might be that that writing less code means
that you don't have a "real" Cocoa app, but this isn't the case.
Core Data simply provides pre-built classes and tools for data
management. You build your custom code on top of this basic set of
functionality.
Core Data is the result of Apple's extensive experience in development tools.
It's a real, industrial-strength framework, and builds heavily on
technologies introduced in Panther, such as Cocoa Bindings.
Although Core Data makes certain things easy, it is not designed for novices.
You should at least be familiar with creating a basic Cocoa application and
Objective-C syntax before reading this tutorial.
Open Xcode 2.0 and Choose File > New Project. The window shown below will appear:
Choose Core Data Application from the Application group and click the Next button.
Name the project BlogDemo. It's important to use this exact name.
Open the Data Model File
In Xcode, open the Models group and double-click the BlogDemo_DataModel.xcdatamodel file, as shown below.
The data modeler window will open but will be blank.
An Entity is similar to a class. In BlogDemo, the Post Entity represents a
post on a blog site. Each Post has a title, a body, a creation date, and an
author.
In a traditional Cocoa application, we would create a Post class, then add
code to make it work. Since this is a Core Data application, we'll
make a Post Entity instead.
An Entity is different from a class in that it doesn't contain code. It's just a description of data. Core Data
uses this description to decide how the application should behave.
1
Between the top and bottom portions of the modeler window, there's a small
plus button. Click it once to create a new Entity.
2
Double-click the default name
"Entity" in the table row and rename it to Post.
Just as an Entity is similar to a class, a Property is similar to an
instance variable. There are three kinds of Properties, but the only one you need to know about for now is Attribute.
An Attribute holds a single value. An Attribute also has a type
associated with it, such as string, number or date. Unlike an instance variable, there is a fixed list
of types that an Attribute can be. This is similar to how SQL databases have column types.
Make sure the Post Entity is selected the far left table view.
1
Click
the plus button under the Properties pane and select Add Attribute from the popup menu
2
Double-click "newAttribute" in the table view and rename it to body.
The third section of the modeler window allows you to fine-tune settings on a
particular Attribute. Select the body attribute to display the third section
of the modeler window.
1
Uncheck "Optional"
2
Choose String from the Type dropdown.
This displays options specific to the String type.
We could add a topic Attribute to Post, but a creating a separate
TopicEntity will give us
the option of making changes to topics without editing each individual post.
1
Once again, click the plus
button at the bottom of the Entity table
2
Rename the Entity to Topic
Add an Attribute to Topic
Add a single Attribute to Topic. Name it title with
a type of String, and deactivate the Optional checkbox.
This may seem like a simplistic Entity, but we can always add to it later.
We now have three Entities, but
they have no connection to each other.
An Attribute can only represent a single value, such as a string, a date,
or a number. To create a link between two Entities, we need to use another
kind of Property, called a Relationship. Relationship is a link between two Entities.
We will create a link from Post to Author, so that
our application can keep track of who created a blog post. First, select the Post Entity so that all of its properties are visible in the
center pane.
1
Click the plus button in
and select Add Relationship from the popup menu. Note how the Kind column says "Relationship".
2
Rename the "newRelationship" to "author"
3
Choose the Author Entity
from the Destination dropdown.
The graphical view should now look like the image to the right.
The arrow tells us that the Relationship
is a link from a post to an author.
Although it looks like the arrow is pointing at the email
Attribute, a Relationship always points to an Entity. The points at which the arrow connects to the entity box is somewhat arbitrary.
Just as we want to keep track of the author of each blog post, we want to track all the
posts for each author. We need to create a Relationshipfrom Author to Post.
In other words, the mirror image of the other Relationship.
First, select the Author Entity so that all of its properties are shown in the center pane.
1
Click the plus button in the center pane
and select Add Relationship
2
Rename the relationship to "posts" (plural)
3
Choose Post
from the Destination dropdown
4
Activate the To-Many Relationship
checkbox. This means that every author will have multiple posts.
The graphical model should now look like the image to the right.
Notice how the Relationship
from Author to Post has two arrows. This indicates that it is a to-many Relationship.
We now have both Relationships set up, but it seems odd to have two separate Relationships when
they are just mirror images of each other. We have the Post's Author and the
Author's Posts. Let's make things easier by combining them.
Verify that the AuthorEntity is still selected so that its Properties
are displayed in the center pane.
1
Select the posts Relationship
2
Select "author" from the Inverse dropdown
Notice how the two Relationship lines have been combined in the graphical representation to the right.
An inverse relationship doesn't just to make things more tidy, it's actually used by Core Data
to maintain data integrity.
Virtually all Relationships should have an inverse version. It makes writing an application
much easier and provides you with features you otherwise wouldn't have.
The last Relationship to create is a link between Post and Topic. The following steps are nearly identical to the previous tasks involving Relationships.
A
Select the Post Entity and click the plus button under the Properties pane.
Choose Add Relationship
B
Rename the Relationship to "topic". Choose Topic from the Destination dropdown
C
Select the Topic Entity and click the plus button under the Properties pane.
Choose Add Relationship
D
Rename the Relationship to "posts" (plural). Choose Post from the Destination dropdown
E
Activate the To-Many Relationship checkbox
F
Select "topic" from the Inverse dropdown
Review
Let's review what we just did. Remember that a Relationship is a link between two entities.
Drag the new MainMenu.nib into
the Xcode project's Resources group, above the other items in that folder. Accept
the default settings for adding the file to the project.
D
Double-click the new MainMenu.nib file in Xcode to
open it in Interface Builder
The contents of the NIB file is shown below.
1
The Posts table. The blog posts
will be listed here by title.
2
Detail view. This is where the contents
of the selected Post will appear.
3
The Author configuration table.
Add, edit and delete Authors here.
4
The Topic configuration table
The NIB document window looks like this:
The blue cube is BlogDemoAppDelegate, which replaces the
MyController class found in conventional Cocoa applications. This class is
automatically created and instantiated in MainMenu.nib when you create a Core Data
application.
We will use Cocoa Bindings to populate the user interface. This is
an easy choice because the Core Data framework is integrated with Cocoa Bindings.
To use bindings, we need to add one NSArrayController instance for each Entity.
Bring up the Controllers palette in Interface Builder, which is shown to the right.
The NSArrayController is the icon with a series of small green boxes in
a single-file line.
1
Drag the NSArrayController icon from the pallete to the document window
We're going to go through this section relatively quickly, as these concepts are
covered extensively in the Cocoa Bindings tutorial.
Bind the Table
Posts Table Column
Bind to:
Posts
Controller Key:
arrangedObjects
Model Key Path:
title
Select the column of the Posts table. You may have to double-click the area several times to get it to appear and select it. After you have it selected, bring up the Bindings section of the Inspector Window. Bind the table column's value as shown in the table to the right.
Connect the Buttons
A
Hold down the Control key and drag a connection from the plus button to the Posts array controller, approving a connection to the add: action
B
Control-drag a connection from the minus button to the Posts array controller, and approve a connection to the remove: action
Bind the Text Boxes
Bind the "value" slots of the title and body text boxes as follows:
Title Text Field
Bind to:
Posts
Controller Key:
selection
Model Key Path:
title
Body Text View
Bind to:
Posts
Controller Key:
selection
Model Key Path:
body
In all three cases, the Model Key Path is the name of the Attribute that
we want to populate the control with.
Review
Here's a quick review of the last section.
A
Added a prebuilt MainMenu.nib file to the project
B
Added and configured
three NSArrayControllers, one for each Entity
in BlogDemo
C
Bound the main
table view's column to the Posts NSArrayController
D
Connected the buttons to the add: and remove: actions on the Posts NSArrayController
E
Bound the
title and body text boxes to their respective Attributes values
Compile and run BlogDemo. Even though we didn't write any code, you can add, modify
and delete records. If you quit and re-run the application, all the
data should return.
Some things are clearly missing, though. The Author and Topic dropdowns don't do anything
yet. The accessory panels are empty too.
In order to assign an Author and Topic to each Post, we need to setup the bindings for the dropdown boxes.
Bind the content, contentValues and selectedObject keys for each dropdown, as shown in
the tables below. Note that selectedObject key binds to a different controller
than the other keys.
Author Dropdown: content
Bind to:
Authors
Controller Key:
arrangedObjects
Model Key Path:
leave empty
contentValues
Bind to:
Authors
Controller Key:
arrangedObjects
Model Key Path:
name
selectedObject
Bind to:
Posts
Controller Key:
selection
Model Key Path:
author
Topic Dropdown: content
Bind to:
Topics
Controller Key:
arrangedObjects
Model Key Path:
leave empty
contentValues
Bind to:
Topics
Controller Key:
arrangedObjects
Model Key Path:
title
selectedObject
Bind to:
Posts
Controller Key:
selection
Model Key Path:
topic
The idea here is to bind the selectedObject key of a dropdown to the name of a Relationship.
Post has a relationship called author, so we bind selectedObject to a model key path of "author". Post also has a Relationship called topic, so we bind the selectedObject of the other dropdown to "topic".
Compile and run BlogDemo. Now that we added bindings to the dropdowns
and the acessory panels, you can create Authors and Topics and
assign them to posts.
If you restart the application, you'll see that all
the data is still intact.
Locate the BlogDemo data file in the Finder. It is placed inside your home directory,
in /Users/<yourname>/Library/Application Support/BlogDemo/BlogDemo.xml
Drag the XML file to the Xcode icon in the dock to view it.
The format is very straightforward. The markup is clear and the element
names reflect Core Data terms. If you'd like to see an
overview of the file structure, open /System/Library/DTDs/CoreData.dtd.
Your application should not edit the data file directly. Always use the
Core Data API to make changes.
Core Data applications use XML data stores by default, but you may want to use a SQLite or
even a standard Binary data store. This is easily done. Open the BlogDemoAppDelegate.m file.
The data store is defined in the -managedObjectContext method, which is generated automatically when
you create the project.
Core Data projects default to using .xml, .sql and .binary, but it's strongly recommended that
you change this to an extension unique to your application, such as .blogdemodoc for BlogDemo.
Data Store Differences
The XML store is most useful during the prototyping phase, when you
want to quickly glance at the data that's being written to disk. It doesn't scale well, though.
The Binary store is generally faster than the XML store, but can't be easily read in a text editor.
The SQLite store is generally the fastest and most scalable store.
The Binary and XML stores
have to load the entire contents of their data files at startup, but the SQLite store can load and
unload data as needed. This can significantly shorten startup time and conserve memory.
You can inspect the contents
of the data file using the command line tool, found at /usr/bin/sqlite3.
The only
drawback of the SQLite store is that it appears to be somewhat slower than the Binary store during
an initial save.
This tutorial was designed to get your first Core Data app running as quickly as possible.
If you'd like to better understand how Core Data is architected, take a look at the Core Data Class Overview article.
As always, let us know what you think about the tutorial.