Core Data Tutorial for iPhone OS

Data Management

2009-09-09

Apple Inc. © 2009 Apple Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Inc., with the following exceptions: Any person is hereby authorized to store documentation on a single computer for personal use only and to print copies of documentation for personal use provided that the documentation contains Apple’s copyright notice. The Apple logo is a trademark of Apple Inc. Use of the “keyboard” Apple logo (Option-Shift-K) for commercial purposes without the prior written consent of Apple may constitute trademark infringement and unfair competition in violation of federal and state laws. No licenses, express or implied, are granted with respect to any of the technology described in this document. Apple retains all intellectual property rights associated with the technology described in this document. This document is intended to assist application developers to develop applications only for Apple-labeled computers. Every effort has been made to ensure that the information in this document is accurate. Apple is not responsible for typographical errors. Apple Inc. 1 Infinite Loop Cupertino, CA 95014 408-996-1010 Apple, the Apple logo, Cocoa, Mac, Objective-C, and Xcode are trademarks of Apple Inc., registered in the United States and other countries. iPhone is a trademark of Apple Inc. Simultaneously published in the United States and Canada.
Even though Apple has reviewed this document, APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS DOCUMENT, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED “AS IS,” AND YOU, THE READER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.

IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS DOCUMENT, even if advised of the possibility of such damages. THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty. Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state.

Contents
Introduction

Introduction 7
Organization of This Document 8

Chapter 1

Starting Out 9
Create the Project 10 Understanding a Core Data–Based Project 10 The Core Data Stack 11 Managed Objects and the Managed Object Context 11 The Managed Object Model 12 Persistent Store Coordinator 13

Chapter 2

The Table View Controller 15
Creating and Defining the RootViewController Class 15 Implementing the RootViewController Class 16 Synthesize the Properties 16 Writing the Accessor Method for the Core Location Manager 16 Implementing viewDidLoad 17 Implement Methods for Memory Management 18 Configuring the Application Delegate 18 Add the Navigation Controller Property 18 Implement the Application Delegate 18 Build and Test 19

Chapter 3

Managed Object and Model 21
Modeling Your Data 21 Add the Entity 21 Add the Attributes 22 Custom Managed Object Class 23 Core Data Recap 24

Chapter 4

Adding Events 25
Implementing the addEvent Method 25 Get the Current Location 25 Create and Configure the Event object 25 Save the New Event 26 Handling Errors 26 Update the Events Array and the Table View 27

3
2009-09-09 | © 2009 Apple Inc. All Rights Reserved.

CONTENTS

Displaying Events in the Table View 27 Build and Test 28 Core Data Recap 29 Chapter 5

Fetching Events 31
Fetching Managed Objects 31 Creating and Executing the Request 32 Create the Request 32 Set the Sort Descriptor 32 Execute the Request 33 Finish Up 33 Build and Test 33 Core Data Recap 33

Chapter 6

Deleting Events 35
Deleting Managed Objects 35 Deleting an Event 35 Build and Test 36 Core Data Recap 36

Chapter 7

Next Steps 37
Where to Go from Here 37 The Core Data Utility Tutorial 37 Use a Fetched Results Controller 37 Creating a Managed Object Model with Xcode 37 A Drill-Down Interface 38 Add an Add Sheet 38

Document Revision History 39

4
2009-09-09 | © 2009 Apple Inc. All Rights Reserved.

and a managed object.Figures Chapter 1 Starting Out 9 Figure 1-1 Figure 1-2 Figure 1-3 Figure 1-4 A simple Core Data stack 11 Managed objects in a context. a table in the database. All Rights Reserved. and a table in the persistent store 12 An entity description. 12 A complex Core Data stack 14 5 2009-09-09 | © 2009 Apple Inc. .

FIGURES 6 2009-09-09 | © 2009 Apple Inc. All Rights Reserved. .

This provides a wealth of basic functionality “for free. Uses a schema to describe the model objects. and for maintaining reciprocal relationships between objects. and delete objects managed by Core Data. Amongst other things. This lets you easily upgrade an old version of the user’s file to the current version. Fundamentally. ■ ■ ■ ■ Core Data is available on iPhone OS v3. but Core Data offers much more than that. . You should read this document to learn how to use Core Data on iPhone. allow the user to make edits in one view that may be discarded without affecting data displayed in another view. This document describes tools and techniques for iPhone OS v3.INTRODUCTION Introduction Core Data is a schema-driven object graph management and persistence framework. Allows you to keep just a subset of your model objects in memory at any given time. This gives you automatic support for undo and redo. for example.0 and later. update.0.” including setting of default values and attribute value validation. This is useful if you want to. Core Data helps you to save model objects (in the sense of the model-view-controller design pattern) to a file and get them back again. This is especially important on iPhone where conserving memory is critical. All Rights Reserved. You define the principal features of your model classes—including the relationships between them—in a GUI-based editor. including: ■ ■ ■ The fundamental design patterns and techniques that underlie Core Data The basics of using the Xcode data modeling tool How to create. and how to commit changes to a data store 7 2009-09-09 | © 2009 Apple Inc. Has an infrastructure for data store versioning and migration. Allows you to maintain disjoint sets of edits of your objects. This is similar to archiving (see Archives and Serializations Programming Guide for Cocoa). it: ■ Provides an infrastructure for managing all the changes to your model objects.

All Rights Reserved. and table views None of these tools and techniques are explained in this tutorial.INTRODUCTION Introduction Important: Core Data is not an entry-level technology. you must understand the basics of iPhone application development. Before starting to use Core Data. Documents you should read to gain adequate experience include: ■ ■ ■ ■ ■ Your First iPhone Application Xcode Workspace Guide Cocoa Fundamentals Guide View Controller Programming Guide for iPhone OS Table View Programming Guide for iPhone OS Organization of This Document This tutorial comprises the following chapters: ■ ■ ■ ■ ■ ■ ■ “Starting Out” (page 9) “The Table View Controller” (page 15) “Managed Object and Model” (page 21) “Adding Events” (page 25) “Fetching Events” (page 31) “Deleting Events” (page 35) “Next Steps” (page 37) The source code for the tutorial is provided in the Locations sample code. including: ■ ■ ■ How to use Xcode and Interface Builder Fundamental design patterns such as model-view-controller and delegation How to use view controllers. navigation controllers. 8 Organization of This Document 2009-09-09 | © 2009 Apple Inc. . so that the content can focus on Core Data itself.

The application you create is conceptually simple—it lets you record your location at any time as an “event. you use Core Data primarily to represent the Event objects and store them in an external file so that they can be displayed when the application launches. and techniques you’ll use in any Core Data–based program.CHAPTER 1 Starting Out The goals of this chapter are to describe the application that you will build. latitude. To add a bit more interest. 9 2009-09-09 | © 2009 Apple Inc. the tutorial also makes use of the Core Location framework. but it does give references to other documents you can read to gain a deeper understanding. and longitude of all the events you’ve recorded. and an Edit button that allows you to delete events from the list. In this tutorial. The goal of this tutorial is to provide a practical introduction to the Core Data framework and how you use it. tools. and for the purposes of this project. The Core Location manager is a very straightforward object.” and uses a table view to show the time. It has an Add button to add a new event. It doesn’t provide in-depth explanations of all the features the framework offers. then to create the Xcode project and to understand the basics of what the Xcode project template gives you. All Rights Reserved. but rather to illustrate the fundamental classes. you don’t need to understand it in any detail. . The aim here is not to create a polished application.

In the Options section. which is where the file containing the application’s data will be located. the first two should be familiar. (Use the General pane of the Info window for the application’s target. . >> Link the project against the Core Location framework. >> In Xcode. @property (nonatomic. @property (nonatomic.(IBAction)saveAction:sender. Call the project “Locations” . @property (nonatomic. Similarly. The model file is described later in “Managed Object and Model” (page 21). retain. readonly) NSManagedObjectModel *managedObjectModel. it provides four other properties and a new method: . retain. 10 Create the Project 2009-09-09 | © 2009 Apple Inc.xcdatamodel) file—typically referred to as the managed object model The application also links against the Core Data framework. readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator.xib) file A Core Data model (. In code listings. the save action method saves the application’s data to disk. although the details of the delegate class will be new. Of the resources. the template provides you with: ■ ■ ■ An application delegate class A MainWindow interface (. Create the Project The only steps in this chapter are to create the project itself and link against the Core Location framework. For now. readonly) NSManagedObjectContext *managedObjectContext. create a new project using the Window-Based Application template in the iPhone OS section. the applicationDocumentsDirectory property simply returns the path to the application’s documents directory. It’s important that you call the project “Locations” so that you can copy and paste code required later in the tutorial. The remaining properties provide access to what’s called the Core Data stack. select the switch to use Core Data for storage. retain.) Understanding a Core Data–Based Project Together with various other supporting files. >> denotes the beginning of a paragraph (sometimes including the following bulleted list) that contains steps that you must perform in the tutorial. examine the header file of the application delegate class. readonly) NSString *applicationDocumentsDirectory. As its name implies. All Rights Reserved. @property (nonatomic. In addition to the standard window and view controller.CHAPTER 1 Starting Out Note: As a convention. comments included in Xcode template files are not shown. Saving is discussed in greater detail throughout this document.

it’s an object representation of a record in a table in a database. a persistent store is like a database. you insert it into a context.) Figure 1-1 (page 11) shows the simplest—and most common—configuration of the stack. and tracks in a music management application. A context represents a single object space. The managed object context is an instance of NSManagedObjectContext. Conceptually. or scratch pad. shapes. (Fetching is discussed in greater detail in “Fetching Events” (page 31). relationship maintenance.) Any changes you make (whether insertion or deletion of complete objects. The Core Data Stack 2009-09-09 | © 2009 Apple Inc. so it’s a model (in the sense of the model-view-controller design pattern) object that is managed by Core Data. The context is a powerful object with a central role in your application. and groups in a drawing application.CHAPTER 1 Starting Out The Core Data Stack Stack is the term used to describe a collection of Core Data framework objects that work together to get modeled objects from and save data to a persistent store—the file where your data is stored. These objects form a group of related model objects that represent an internally consistent view of one or more persistent stores. You fetch existing records in the database into the context as managed objects. (One of the store types you can use with Core Data is SQLite. in an application. All Rights Reserved. artists. with responsibilities from life-cycle management to validation. but the store doesn’t have to be an actual database. Conceptually. Figure 1-1 A simple Core Data stack Managed Object Context A collection of managed objects Persistent Store Coordinator A collection of stores Persistent Object Store A collection of object data Managed Object Model A collection of entity descriptions Store File The objects you usually work directly with are at the top of the stack—the managed object context and the managed objects it contains. albums. Its primary responsibility is to manage a collection of managed objects. A managed object is always associated with a managed object context. text areas. and undo/redo. Managed Objects and the Managed Object Context A managed object is an instance of NSManagedObject or of a subclass of NSManagedObject. Managed objects represent the data you operate on in your application—for example departments and employees in a human resources application. with tables and records. 11 . or manipulation of property values) are kept in memory until you actually commit them to the store by saving the context. When you create a new managed object.

. and what properties (attributes and relationships) it has. 12 The Core Data Stack 2009-09-09 | © 2009 Apple Inc. All Rights Reserved. A model is a collection of entity description objects (instances of NSEntityDescription). the name of the class used to represent the entity in your application. Figure 1-3 An entity description.CHAPTER 1 Starting Out Figure 1-2 (page 12) illustrates a managed object context that contains two managed objects corresponding to two records in an external database. In one of the objects. a table in the database. a property value has been changed in memory. and a managed object. Figure 1-2 Managed objects in a context. It’s an object representation of a schema that describes your database. and a managed object corresponding to a single record in the table. An entity description describes an entity (a table in a database) in terms of its name. and a table in the persistent store Managed Object Context Employee name Fred salary 90000 Employee name Nigel salary 60000 Unsaved data Employee name salary Fred 90000 Juli 97000 Nigel 50000 Tanya 56000 Current data The Managed Object Model A managed object model is an instance of NSManagedObjectModel. Figure 1-3 (page 12) illustrates the relationship between an entity description in a model. but the change has not been committed to the database. Name Managed Object Class Attribute Attribute Entity Description “Employee” NSManagedObject name salary name Fred salary 97000 entityDescription Managed Object Every managed object has a reference to the entity of which it is an instance. and so the managed objects you use in your application. a table in the database.

CHAPTER 1 Starting Out Core Data uses the model to map between managed objects in your application and records in the database. A persistent object store represents an external store (file) of persisted data.) A persistent store coordinator is an instance of NSPersistentStoreCoordinator. see Persistent Store Features in Core Data Programming Guide. There are different classes of persistent object store for the different file types that Core Data supports. In an iPhone application. When you fetch records. To learn more about persistent stores and the different types. 13 . Core Data won’t be able to read stores you created using the previous model. This section describes the persistent store coordinator in detail. Core Data retrieves results from all of them (unless you specify which store you’re interested in). you might have multiple managed object contexts. You can also implement your own if you want to support a custom file type—see Atomic Store Programming Topics. You might want to maintain discrete sets of managed objects and edits to those objects. In any application. The persistent store coordinator’s role is to manage these stores and present to its managed object contexts the façade of a single unified store. All Rights Reserved. Each of these would be connected to the same coordinator. but in complex desktop applications there may be several. (This is something common to many persistence mechanisms.) Persistent Store Coordinator The persistent store coordinator plays a central role in how Core Data manages data. It’s important to be aware that if you change the schema in your application. or you might want to perform a background operation using one context while allowing the user to interact with objects in another. you don’t often interact with the coordinator directly when you use the framework. however. Figure 1-4 (page 14) illustrates the role the coordinator plays. each potentially containing different entities. does also provide an infrastructure for managing such changes—see the Core Data Model Versioning and Data Migration Programming Guide. (The persistent store coordinator is also described in Core Data Basics in the Core Data Programming Guide. you usually just have a single store. though. The Core Data Stack 2009-09-09 | © 2009 Apple Inc. Core Data. so if you prefer you can skip it and refer to it later as necessary. It manages a collection of persistent object stores. It’s the object that actually maps between objects in your application and records in the database. Stacks aren’t usually this complicated.

CHAPTER 1 Starting Out Figure 1-4 A complex Core Data stack Managed Object Context Employee Customer Department Contractor Managed Object Context Employee Department Customer Persistent Store Coordinator Managed Object Model A collection of entity descriptions Persistent Object Store Persistent Object Store Persistent Object Store 14 The Core Data Stack 2009-09-09 | © 2009 Apple Inc. All Rights Reserved. .

A Core Location manager. The table view controller displays the array of event objects. which contains the collection of event objects that the table view controller displays. and updated as the user adds and removes events. ■ ■ ■ Creating and Defining the RootViewController Class First. It’s assumed that you’re already familiar with view controllers and table views. so it must adopt the CLLocationManagerDelegate protocol. All Rights Reserved. and to update the application delegate to create and configure an instance of the table view controller. creating an instance of a navigation controller and a table view controller. the controller adds four properties to the basic table view controller: ■ A mutable array. for the events array. and displaying a navigation controller and a table view controller. which the user needs to add events. call it RootViewController. A bar button item. In the next chapter. If any of this is too challenging. This provides the architecture for the application. the Core Location manager. configuring. which provides location information to the application. >> In Xcode.CHAPTER 2 The Table View Controller The goal of this chapter is to create an initial implementation of the table view controller. you should stop here and practice writing some more applications before continuing. To support this. Next. add four properties. The application delegate is responsible for creating. The root view controller serves as the Core Location manager’s delegate. 15 . This chapter sets up the table view. A managed object context. create files for the new class. which serves as your gateway to the Core Data stack. The user can add new events only when this is active (the iPhone Simulator simulates activity so you don’t need to install the application on a device to test it). create a new UITableViewController subclass. you’ll use Core Data to manage the actual data. and an Add button. the managed object context. >> Replace the contents of the RootViewController header file with the following: #import <CoreLocation/CoreLocation. and configuring the Core Location manager. this chapter does not provide significant detail or explanation beyond that you need to understand the role of each of the components in the application. You need a reference to the button so you can conditionally enable and disable it in response to changes in the Core Location manager’s state. It’s populated from the application’s persistent store when the application starts up.h> Creating and Defining the RootViewController Class 2009-09-09 | © 2009 Apple Inc.

@property (nonatomic. @property (nonatomic. } 16 Implementing the RootViewController Class 2009-09-09 | © 2009 Apple Inc.(CLLocationManager *)locationManager { if (locationManager != nil) { return locationManager. retain) CLLocationManager *locationManager. Implement methods to take care of memory management. locationManager. Synthesize the Properties >> Add these lines: @synthesize @synthesize @synthesize @synthesize eventsArray. replacing implementations provided by the template as appropriate. retain) UIBarButtonItem *addButton. Writing the Accessor Method for the Core Location Manager >> Create an accessor method to dynamically create the Core Location manager on demand: .CHAPTER 2 The Table View Controller @interface RootViewController : UITableViewController <CLLocationManagerDelegate> { NSMutableArray *eventsArray. Implement viewDidLoad to set up the Core Location manager and the Add and Edit buttons. retain) NSManagedObjectContext *managedObjectContext. All the code described in the following sections goes into the @implementation block of the RootViewController class. } @property (nonatomic. managedObjectContext. Write the accessor method for the Core Location manager and implement two of its delegate methods. NSManagedObjectContext *managedObjectContext. All Rights Reserved. UIBarButtonItem *addButton. you need to: ■ ■ ■ ■ Synthesize the properties you declared. . retain) NSMutableArray *eventsArray. @end Implementing the RootViewController Class There are several parts to the initial implementation. addButton. @property (nonatomic. CLLocationManager *locationManager.

// Set up the buttons. } Implementing viewDidLoad The viewDidLoad method needs to set up the Core Location manager and the Add and Edit buttons.(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { addButton. self.leftBarButtonItem = self. addButton. then disable the button. } Implementing the RootViewController Class 2009-09-09 | © 2009 Apple Inc.CHAPTER 2 The Table View Controller locationManager = [[CLLocationManager alloc] init]. return locationManager.enabled = NO.title = @"Locations".editButtonItem. >> Replace the implementation of viewDidLoad with the following: .(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { addButton. >> Add the following two Core Location manager delegate methods: . [[self locationManager] startUpdatingLocation].(void)viewDidLoad { [super viewDidLoad]. then enable the button.rightBarButtonItem = addButton. All Rights Reserved. self. 17 . } . locationManager.delegate = self. addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addEvent)]. locationManager.enabled = YES. If the Core Location manager is generating updates.enabled = NO. // Start the location manager. self.navigationItem.desiredAccuracy = kCLLocationAccuracyNearestTenMeters. // Set the title.navigationItem. implement two delegate methods to enable and disable the Add button as appropriate. if the Core Location manager is failing. } Next.

CHAPTER 2 The Table View Controller Implement Methods for Memory Management >> Replace the existing implementations of viewDidUnload and dealloc. } . >> In the application delegate’s header file (LocationsAppDelegate.(void)dealloc { [managedObjectContext release].eventsArray = nil. create an instance of RootViewController and a navigation controller to contain it. self. >> Add the property declaration: @property (nonatomic. You also need to pass the application’s managed object context to the new root view controller. [addButton release].addButton = nil. . } Configuring the Application Delegate The application delegate is responsible for creating and configuring the root view controller and a navigation controller to contain it. [locationManager release]. 18 Configuring the Application Delegate 2009-09-09 | © 2009 Apple Inc. Synthesize the navigationController property. . self. Implement the Application Delegate In the application delegate’s implementation file (LocationsAppDelegate. Add the Navigation Controller Property You need to add a property for the navigation controller. add an instance variable: UINavigationController *navigationController. retain) UINavigationController *navigationController.h). The implementation of viewDidUnload should relinquish ownership of anything created in viewDidLoad that can be recreated. you need to: ■ ■ ■ Import the RootViewController’s header file.(void)viewDidUnload { self. In the applicationDidFinishLaunching: method.locationManager = nil. [eventsArray release]. All Rights Reserved. [super dealloc].m).

import the RootViewController class’s header file: #import "RootViewController. UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController]. 19 . >> Replace your application delegate’s applicationDidFinishLaunching: method with the following implementation: .h" >> In the @implementation block of the application delegate class. [window addSubview:[navigationController view]].managedObjectContext = context.CHAPTER 2 The Table View Controller >> Before the @implementation block of the application delegate class.navigationController = aNavigationController. RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain]. rootViewController. } Build and Test At this stage you should build and test the project to make sure that it all works. [window makeKeyAndVisible]. [aNavigationController release]. [rootViewController release]. } // Pass the managed object context to the view controller.(void)applicationDidFinishLaunching:(UIApplication *)application { // Configure and show the window. All Rights Reserved. self. It should display a blank table view with a navigation bar. if (!context) { // Handle the error. The navigation bar should contain the Edit and Add buttons: Build and Test 2009-09-09 | © 2009 Apple Inc. synthesize the navigation controller property: @synthesize navigationController. NSManagedObjectContext *context = [self managedObjectContext].

though. If you tap it. Before you can add an event. the application will of course crash since you haven’t yet implemented the addEvent method. . you need to define the Event entity.CHAPTER 2 The Table View Controller The Add button will initially be disabled. That’s what you’ll do next. All Rights Reserved. 20 Build and Test 2009-09-09 | © 2009 Apple Inc. but after a few seconds it should become enabled (as the location manager starts sending events).

CHAPTER 3 Managed Object and Model The goal of this chapter is to allow users to create a new event when they tap the Add button. you need to define the Event entity in the managed object model. Modeling Your Data As noted in “The Managed Object Model” (page 12). Now you can set the name for the new entity. There are actually several ways to edit the constituent parts of the model. and create an instance of the class in the add method. 21 . All Rights Reserved. >> Make sure you have the new entity selected in the entity pane so that you see information about the entity in the detail pane at the right. latitude. and longitude. To do this. in the Resources group select the model file (Locations. and a graphical representation of the entity (a rounded rectangle) appear in the diagram view. You can also use the Add button (+) at the lower left of the entity pane. implement the corresponding class.xcdatamodel) to display the model editor. You can create the model programmatically. with three attributes—creation date. see Xcode Tools for Core Data. To learn more about the modeling tool. Add the Entity First. (Don’t change the class name. and other ways to edit the model. Change the name of the entity to Event. >> Choose Design > Data Model > Add Entity to add a new entity to the model. an Event. these steps typically describe just one. add an Event entity. or use the Xcode modeling tool to create the model graphically. in a similar way to that in which you create a user interface using Interface Builder. This application has just a single entity. You should see a new entry for the entity (called “Entity”) appear in the entity pane at the top left of the document editor. or use the shortcut menu within the diagram view in the model editor. >> In Xcode. the model is a collection of entity and property description objects that tell Core Data about the managed objects in your application.) Your model should look similar to this: Modeling Your Data 2009-09-09 | © 2009 Apple Inc.

Indeed. so the class name doesn’t have to be the same as the entity name. You should see a new attribute (called newAttribute) appear in the property pane. add the attribute for the creation date. then choose Design > Data Model > Add Attribute twice (to add two attributes). in some cases several entities may be represented by the same class—NSManagedObject. . and select Date from the Type pop-up menu. All Rights Reserved. Core Data uses the entity description to find out about the data objects it manages. >> Make sure you have selected Event in the entity pane. Now add attributes for latitude and longitude. then in the detail pane change the name of the attribute to creationDate. Add the Attributes First. >> Make sure you have selected Event in the entity browser. You don’t need to set any of the other values. Core Data is able to differentiate the instances on the basis of their associated entity description. then choose Design > Data Model > Add Attribute. >> Make sure you have selected the new attribute in the property pane. 22 Modeling Your Data 2009-09-09 | © 2009 Apple Inc.CHAPTER 3 Managed Object and Model There’s an important difference between the name of the entity and the name of the Objective-C class used to represent instances of the entity. You need to set its name and type.

In the New File dialog. >>Choose File > New File. and in the detail pane change the Name of the attribute to longitude. then in the detail pane select Double from the Type pop-up menu.CHAPTER 3 Managed Object and Model >> Select both the new attributes in the property pane. select the Event entity (the selection is used to indicate which items to create subclasses for). >>In Xcode. the Managed Object Class may be available in the iPhone OS section under Cocoa Touch Classes. All Rights Reserved. Depending on the version of Xcode you’re using. in the model. or you may need to choose the template in the Mac OS X section. Click Next to accept them. >> Select just the first new attribute in the property pane. The correct location and targets should have been selected for you. select Managed Object Class. under Cocoa—either will work correctly. Your model should look similar to this: Custom Managed Object Class You can now use Xcode to generate the files for a custom class to represent the Event entity. 23 . >> Select just the second new attribute in the property pane. >>Click Next. and in the detail pane change the Name of the attribute to latitude. Custom Managed Object Class 2009-09-09 | © 2009 Apple Inc.

Because the model was changed. In the next chapter. because the table view controller is going to make use of the new class. (If you add your own instance variables that do not have corresponding properties in the managed object model. the property values at runtime are instances of NSNumber. All Rights Reserved. however Core Data generates the accessor methods at runtime. however Core Data is responsible for the life-cycle of all modeled properties of a managed object.CHAPTER 3 Managed Object and Model You should see the Entity selection pane. Finally. import its header file in the table view controller’s implementation file. >>In the table view controller’s implementation file (RootViewController. . after the initial import statement. Normally you might expect to see a dealloc method to release instance variables.) ■ The model is also updated—the Event entity is now represented by the Event class. The Event class interface and implementation files are created and added to your project. you’ll create instances of the entity. see Xcode Tools for Core Data. there is no dealloc method. you need to save it. There are a few things to notice: ■ In the interface file (Event. then you need to manage those yourself as normal. You then created a custom class to represent that entity. Although you specified the latitude and longitude attribute types as Double.m). >>Click Finish to generate the files. Normally you might expect to see synthesized.m). >>Save the model file.0 properties” options should also be selected.h). add: #import "Event. the properties are implemented as dynamic. ■ In the implementation file (Event. 24 Core Data Recap 2009-09-09 | © 2009 Apple Inc. If you want to learn more about the modeling tools.h" Core Data Recap You used the Xcode data modeling tool to create a new entity. with the Event entity selected. Core Data uses objects to represent values. ■ In the implementation file (Event. The “Generate accessors” and “Generate Objective-C 2. all the attributes are represented by object values.m).

(void)addEvent. It has to: ■ ■ ■ ■ Get the current location Create an Event object and configure it using the current location information Save the Event object Update the events array and the user interface First. Get the Current Location When you create a new Event object. Implementing the addEvent Method You create new Event objects in the addEvent method. then don’t continue. You get the location from the location manager. If it’s not able to provide a location. Recall that it’s invoked when the user taps the Add button (see “Implementing viewDidLoad” (page 17)). } } Create and Configure the Event object You typically create a managed object using a convenience method—insertNewObjectForEntityForName:inManagedObjectContext:—of NSEntityDescription. which returns a properly initialized instance of the correct class for the entity you Implementing the addEvent Method 2009-09-09 | © 2009 Apple Inc. All Rights Reserved.CHAPTER 4 Adding Events The goal of this chapter is to create the application logic to allow the user to create new event objects and display them in the user interface. There are several parts to the method. you need to set its location. 25 . >> Add a declaration of the addEvent method to the RootViewController header file: . if (!location) { return.(void)addEvent { CLLocation *location = [locationManager location]. >> Add the following to RootViewController implementation file: . declare the addEvent method. though.

In a scenario as simple as that described in “Save the New Event” (page 26)—where the only change you expect is the addition of a single object—if the data can’t be saved it’s likely to be indicative of some sort of catastrophic failure from which recovery might be difficult or impossible.latitude]]. here you can use date method of NSDate to get a date object representing the current date and time. [event setCreationDate:[NSDate date]]. All Rights Reserved. you save changes as soon as the user has made them. inserted into the managed object context.longitude]]. Handling Errors It’s up to you to decide how you handle a Core Data error. it’s just that the return value from the save: method and the error parameter tend to bring into sharper focus the possibility of a problem occurring. the NSManagedObjectContext save: method takes an error parameter and returns a Boolean value to indicate success or failure. You get the latitude and longitude from the location as scalar values. Whatever changes you make—whether editing property values or adding or deleting whole objects—aren’t actually committed to the persistent store (file) until you save the context. >> Add the following code at the end of the current implementation of addEvent: // Create and configure a new instance of the Event entity Event *event = (Event *)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:managedObjectContext]. Save the New Event Remember that the managed object context acts like a scratch pad (see “Managed Objects and the Managed Object Context” (page 11)). You could get the time stamp from the location as well. Instead. see Managed Objects in Core Data Programming Guide). CLLocationCoordinate2D coordinate = [location coordinate]. } In common with several Core Data methods. if (![managedObjectContext save:&error]) { // Handle the error. but this is a constant value on the simulator. in an iPhone application. Typically. so you need to convert these to NSNumber objects for the Event object. The situation is really no different from that in any other application. >> Add the following code at the end of the current implementation of addEvent: NSError *error. just as you would any other object. After you’ve created the object. [event setLatitude:[NSNumber numberWithDouble:coordinate.CHAPTER 4 Adding Events specify. . [event setLongitude:[NSNumber numberWithDouble:coordinate. In this situation you might just present an alert sheet telling the user to restart the application. 26 Implementing the addEvent Method 2009-09-09 | © 2009 Apple Inc. you can set its property values using accessor methods. (For more about the initialization process .

Update the Events Array and the Table View Finally. 27 . you can interrogate the error object to find out what went wrong.(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [eventsArray count]. } Next. then scroll the table view to show the new row. All Rights Reserved. What information should you present to the user? What options might you give them for recovering from the problem? These are not questions that Core Data is able to answer. >> Replace the implementation of tableView:(UITableView *)tableView cellForRowAtIndexPath: with the following: Displaying Events in the Table View 2009-09-09 | © 2009 Apple Inc. If you have more than one managed object context. Displaying Events in the Table View You need to update two table view data-source methods to display the events. add a corresponding row to the top of the table view. so you don’t need to test the section number): .CHAPTER 4 Adding Events In a more complex scenario. then update the table view. First simply tell the table view how many events to display. but most of it is related to user interface and display rather than data management. >> Add the following code at the end of the current implementation of addEvent: [eventsArray insertObject:event atIndex:0]. or added or deleted managed objects in such a way that either an individual object is in an inconsistent state (validation fails) or the object graph as a whole is inconsistent. the user might have changed property values. [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES]. >> Update the implementation of tableView:numberOfRowsInSection: to return the number of objects in the events array (there’s only one section. you need to add the new Event object to the events array. You should think carefully about what the user experience should be in the event of an error occurring. Since this is a new Event. add the new object to the beginning of the events array. In general.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]. and Events are displayed with most recent events at the top of the list. You’ll see there is a nontrivial amount of code. it’s also possible that the persistent store was updated when changes made in a different context were committed and so the objects in the current context are inconsistent with the corresponding records in the store. you need to configure the table view cells to display information about each event. NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]. The next task is to complete the implementation of the table view data-source methods to display the events. [self.

text = [dateFormatter stringFromDate:[event creationDate]].row].detailTextLabel. [dateFormatter setTimeStyle:NSDateFormatterMediumStyle]. // Dequeue or create a new cell UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]. [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle]. [dateFormatter setDateStyle:NSDateFormatterMediumStyle].(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // A date formatter for the time stamp static NSDateFormatter *dateFormatter = nil. if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]. } // A number formatter for the latitude and longitude static NSNumberFormatter *numberFormatter = nil. [numberFormatter stringFromNumber:[event longitude]]]. 28 Build and Test 2009-09-09 | © 2009 Apple Inc. until you tap the Add button—at which point it will crash.CHAPTER 4 Adding Events . return cell. [numberFormatter stringFromNumber:[event latitude]]. } Event *event = (Event *)[eventsArray objectAtIndex:indexPath.textLabel. cell. cell. it should compile without errors. . } static NSString *CellIdentifier = @"Cell". if (dateFormatter == nil) { dateFormatter = [[NSDateFormatter alloc] init]. NSString *string = [NSString stringWithFormat:@"%@. } Build and Test If you build the project.text = string. [numberFormatter setMaximumFractionDigits:3]. %@". The application should also launch and run correctly. if (numberFormatter == nil) { numberFormatter = [[NSNumberFormatter alloc] init]. This is because the events array hasn’t been created yet. >> Solely for testing purposes. All Rights Reserved. add the following line to the end of the RootViewController object’s implementation of viewDidLoad: eventsArray = [[NSMutableArray alloc] init].

■ To commit changes to the persistent store. Core Data Recap 2009-09-09 | © 2009 Apple Inc. If you quit and relaunch the application. you should find that if you tap the Add button new events are displayed in the table view. if you add or modify objects. It’s up to you to decide how to deal with any error that might occur during a save operation. the changes are held in memory until you invoke save:. restore the project to its pre-testing state. Before doing that. This is your task in the next chapter. though. you need to populate the events array on launch with the existing Event objects. This method ensures that you get a properly initialized instance of the class that represents the entity you specify. you need to save the managed object context. just as you would any other object. and not much related directly to Core Data. >> Delete the line you added for testing. ■ You get and set a managed object’s property values using accessor methods. All Rights Reserved.CHAPTER 4 Adding Events If you build and run now. 29 . The context acts as a scratch pad. The important points are that: ■ You typically create a new managed object using the convenience method insertNewObjectForEntityForName:inManagedObjectContext: of NSEntityDescription. but using accessor methods is much more efficient (see Using Managed Objects in Core Data Programming Guide). You can also use key-value coding. Core Data Recap There was a lot of code in this chapter. just as you would any other object. To remedy this. you won’t see the list of Events when it starts up.

All Rights Reserved.CHAPTER 4 Adding Events 30 Core Data Recap 2009-09-09 | © 2009 Apple Inc. .

) The sort order is represented by an array of NSSortOrdering objects. As a minimum. in a corporate information application. A fetch request is an instance of NSFetchRequest. you can also use a fetched results controller—NSFetchedResultsController—to manage a result set for you. Execute fetch request Entity (table name) Employee Predicate (optional) salary > 60000 Sort orderings (optional) name: ascending alphabetical Fetch Request Managed Object Context Returns Persistent Store Coordinator Array Query Response Persistent Object Store name salary Managed Object Fred 97000 name salary Managed Object Juli 90000 Unless you really need all the objects of a particular entity. you should use a predicate to limit the number of objects returned to those you’re actually interested in. It may also specify any constraints on the values that the objects should have and what order you want them back in. All Rights Reserved. whose salary is greater than a certain amount. it specifies the entity you’re interested in. 31 . (For more about predicates see Predicate Programming Guide. Fetching Managed Objects To fetch objects from a persistent store. (If you’re displaying objects in a table view. ordered by name. For example.CHAPTER 5 Fetching Events The goal of this chapter is to fetch existing Event objects when the application launches. you need a managed object context and a fetch request. The constraints are represented by a predicate—an instance of NSPredicate. you might create a fetch request to retrieve Employee objects.) Fetching Managed Objects 2009-09-09 | © 2009 Apple Inc. It works hard to ensure that as little data as possible is held in memory.

but it’s much more convenient to use the class method. Because you might want to specify multiple sort orderings (for example. you need to put the sort descriptor in an array. last name. you therefore need to specify a sort descriptor for the fetch. then Core Data fetches the Department for you if it hadn’t already been fetched. the method then asks for the (managed object) context’s (persistent store) coordinator’s (managed object) model and retrieves from that the entity with the name you specified (you can refer back to “The Core Data Stack” (page 11) to see a pictorial representation). Add the sort descriptor to the array.CHAPTER 5 Fetching Events Note that you don’t always need to execute a fetch to retrieve objects. 32 Creating and Executing the Request 2009-09-09 | © 2009 Apple Inc. [request setSortDescriptors:sortDescriptors]. Core Data. Set the Sort Descriptor If you don’t specify a sort descriptor. . if you execute a fetch to retrieve an Employee object. if necessary. For example. You provide the name of the entity you want and the managed object context you’re dealing with. NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:managedObjectContext]. [request setEntity:entity]. automatically retrieves objects that are at the destination of a relationship. the order in which objects are returned from a fetch is undefined. [sortDescriptor release]. [sortDescriptors release]. All Rights Reserved. Create the Request Create a fetch request and set the entity. >> Add the following code at the end of the current implementation of viewDidLoad: NSFetchRequest *request = [[NSFetchRequest alloc] init]. nil]. Conceptually it’s not very difficult (you just navigate down the stack). The events array needs to be mutable since the user can add and remove events. and first name). and set the array as the fetch request’s sortDescriptors array: NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:NO]. Creating and Executing the Request When the table view controller loads its view. >> At the end of the current implementation of viewDidLoad. NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor. it should fetch the Event objects and keep them in the events array so that they can be displayed later. To retrieve the Events in chronological order. and you could do it yourself easily enough. you might want to sort employees by department. create a sort descriptor to order Event objects by creation date—most recent first—and a mutable array. The method of interest here is NSEntityDescription’s entityForName:inManagedObjectContext:. then ask it for its related Department.

>> Add the following code at the end of the current implementation of viewDidLoad: NSError *error. >> Add the following code at the end of the current implementation of viewDidLoad: [self setEventsArray:mutableFetchResults]. you should find that it compiles correctly and that existing Event objects are displayed when the application launches. Build and Test If you build and run the application. [mutableFetchResults release]. you need to specify an entity. Build and Test 2009-09-09 | © 2009 Apple Inc.) Execute the Request Having created a fetch request. 33 . you now execute it. this example leaves it up to you to decide how to handle any error (see “Handling Errors” (page 26)). All Rights Reserved. As a minimum. so make a mutable copy of the result. You might also specify a predicate and an array of sort orderings. [request release]. Finish Up The final steps are to set the view controller’s events array instance variable and to release objects that were allocated.CHAPTER 5 Fetching Events (It’s often useful to use the initWithObjects: method of NSArray in case you want to add more sort descriptors later. } As previously. Core Data Recap The important points from this chapter are that: ■ You fetch managed objects by creating a fetch request. You get the entity using the convenience method entityForName:inManagedObjectContext: of NSEntityDescription. The events array needs to be mutable. if (mutableFetchResults == nil) { // Handle the error. NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy].

■ You don’t always need to explicitly fetch managed objects. . Core Data fetches the Department for you if it hasn’t already been fetched. automatically retrieves objects that are at the destination of a relationship.CHAPTER 5 Fetching Events To ensure that you retrieve no more objects than necessary (and so keep memory usage down). then ask it for its related Department. since there are no relationships in this tutorial. you should typically try to constrain your request as narrowly as possible using a predicate. For example. 34 Core Data Recap 2009-09-09 | © 2009 Apple Inc. All Rights Reserved. though: Core Data. if you execute a fetch to retrieve an Employee object. if necessary. This wasn’t addressed directly in code. To repeat the point made earlier.

it doesn’t mean a record automatically is created for that object in the database—you need to save the context.(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // Delete the managed object at the given index path. Save the changes. [eventsArray removeObjectAtIndex:indexPath.row]. Similarly. 2. 3. you tell the managed object context to mark an object as deleted. It needs to do three things: 1. >> In the RootViewController implementation file. simply because an object is deallocated does not mean that the corresponding record itself is destroyed. If you create a managed object. NSManagedObject *eventToDelete = [eventsArray objectAtIndex:indexPath. you implement the table view data source method tableView:commitEditingStyle:forRowAtIndexPath:. using the deleteObject: method of NSManagedObjectContext. Deleting an Event To handle deletion. Then to actually destroy the record. Update the table view. you commit the action using save:.CHAPTER 6 Deleting Events The goal of this chapter is to allow the user to delete events from the list. Deleting Managed Objects 2009-09-09 | © 2009 Apple Inc. implement the tableView:commitEditingStyle:forRowAtIndexPath: method as follows: . It should do this only if the action is a delete. the lifetime of a record in the database is not tied to the lifetime of a given managed object. All Rights Reserved. 35 . Delete the selected object. To delete a record. // Update the array and table view. Deleting Managed Objects As you saw when you created a new managed object.row]. [managedObjectContext deleteObject:eventToDelete].

. // Commit the change. Created an instance of a managed object. if (![managedObjectContext save:&error]) { // Handle the error. Deleted a managed object. If you tap Edit. Although you have access to the other objects in the stack. you often don’t need to use them directly. You can start investigating ways to enhance your knowledge and understanding of Core Data. Fetched managed objects. You should find that it compiles and runs without error. You’ve now completed the tutorial. NSError *error. } } } Build and Test Build and test the application. in performing these tasks.CHAPTER 6 Deleting Events [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES]. All Rights Reserved. Some suggestions are given in the next chapter. the only object in the Core Data stack (see “The Core Data Stack” (page 11)) with which you interacted directly was the managed object context. Core Data Recap You’ve now performed the basic tasks you need to be familiar with to use Core Data—you: ■ ■ ■ ■ Created an entity in a managed object model. the table view should enter edit mode. 36 Build and Test 2009-09-09 | © 2009 Apple Inc. If you delete a row. or you use a convenience class method to accomplish a particular task that would otherwise require you to access them. Either the Xcode template takes care of setting them up. If you quit and relaunch the application. the row you deleted should no longer be visible. You may have noticed that. You also created a custom class to represent the entity. it should be properly deleted from the table view. You also changed some of its property values.

Creating a Managed Object Model with Xcode Work through the tutorial Creating a Managed Object Model with Xcode. but it’s freed from the distraction of a user interface.CHAPTER 7 Next Steps The goal of this chapter is to suggest what steps you might take next to enhance your understanding of Core Data and how you can use it in future applications. It introduces a couple of new concepts regarding the lifecycle of a managed object. First. though. and in particular how to establish relationships between entities. Use a Fetched Results Controller Turning back to iPhone. For comparison. 37 . look at the CoreDataBooks example. and reinforces the idea of the managed object model being just a collection of objects—by having you create one programatically. This is an issue that you might address as your experience grows (see Core Data Model Versioning and Data Migration Programming Guide). there are some easier steps to take. This will be essential if you want to create applications that contain entities that are related to each other. You will learn more about the Xcode tools for Core Data. One important item to remember is that. try to update the Locations application to use an NSFetchedResultsController object. It’s similar in many respects to this tutorial. As you explore. if you change the schema in your managed object model. your application typically won’t be able to open files you created with an earlier version. as suggested in “A Drill-Down Interface” (page 38). A fetched results controller is intended primarily to make fetching large numbers of objects much more efficient. The Core Data Utility Tutorial It’s worth turning away from the iPhone for a short while and working through Core Data Utility Tutorial. All Rights Reserved. you can turn to the Core Data Programming Guide for help. but it’s worth practicing using one with a smaller data set. Where to Go from Here 2009-09-09 | © 2009 Apple Inc. Where to Go from Here Here are some suggestions for ways in which you can enhance your understanding of Core Data and how you can integrate it in your applications.

The TaggedLocations sample provides an example of using a second entity with a to-many relationship. If you ask an event for its photo.) 38 A Drill-Down Interface 2009-09-09 | © 2009 Apple Inc. with a relationship from the Event entity to the Photo entity (and a reciprocal relationship from the photo to the event) When you retrieve just a single Event object. See PhotoLocations for an example. You would typically model the photograph as a separate entity. Think also about how you might keep the edits made to the Event object in the Add sheet discrete from edits made in the rest of the application. Core Data has a feature called faulting (see Managed Objects in Core Data Programming Guide) which means that it doesn’t have to complete the object graph. the photo relationship may be represented by a fault. and perhaps a second entity. Core Data automatically fulfills the fault and retrieves the corresponding data for you. All Rights Reserved.CHAPTER 7 Next Steps A Drill-Down Interface Extend the Locations application to provide a drill-down interface to allow users to inspect an event—perhaps to edit comments or a add photograph. If you add a photograph. (Hint: you might consider using two managed object contexts—see the CoreDataBooks example. You need to add more properties to the Event entity. . consider the memory management implications of fetching a photograph with every Event you retrieve from the store. Add an Add Sheet An Add sheet allows you to enter more information about an event when you create it. Think about what information you might pass to the Add sheet controller.

. First version of a tutorial that introduces application development for iPhone using Core Data. Added a missing line of code to the implementation of applicationDidFinishLaunching:.REVISION HISTORY Document Revision History This table describes the changes to Core Data Tutorial for iPhone OS. Corrected typographical errors. 2009-03-15 39 2009-09-09 | © 2009 Apple Inc. All Rights Reserved. Date 2009-09-09 2009-06-04 2009-03-19 Notes Corrected links to sample applications.

All Rights Reserved. .REVISION HISTORY Document Revision History 40 2009-09-09 | © 2009 Apple Inc.

Sign up to vote on this title
UsefulNot useful