Working with iOS 4 iPhone Databases using Core Data (Xcode 4)

From Techotopia
Revision as of 20:15, 27 October 2016 by Neil (Talk | contribs) (Text replacement - "<table border="0" cellspacing="0"> " to "<table border="0" cellspacing="0" width="100%">")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
PreviousTable of ContentsNext
An Example SQLite based iOS 4 iPhone Application (Xcode 4)An iOS 4 iPhone Core Data Tutorial (Xcode 4)


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

The preceding chapters covered the concepts of database storage using the SQLite database. In these chapters the assumption was made that the iPhone application code would directly manipulate the database using SQLite C API calls to construct and execute SQL statements. Whilst this is a perfectly good approach for working with SQLite in many cases, it does require knowledge of SQL and can lead to some complexity in terms of writing code and maintaining the database structure. This complexity is further compounded by the non-object-oriented nature of the SQLite C API functions. In recognition of these shortcomings, Apple introduced Core Data. Core Data is essentially a framework that places a wrapper around the SQLite database (and other storage environments) enabling the developer to work with data in terms of Objective-C objects without requiring any knowledge of the underlying database technology.

We will begin this chapter by defining some of the concepts that comprise the Core Data model before providing an overview of the steps involved in working with this framework. Once these topics have been covered, the next chapter will work through an iOS 4 iPhone Core Data Tutorial.


Contents


The Core Data Stack

Core Data consists of a number of framework objects that integrate to provide the data storage functionality. This stack can be visually represented as illustrated in the following diagram:


Core Data Stack Architecture diagram <google>IOSBOX</google>

As we can see from the above figure, the iOS iPhone based application sits on top of the stack and interacts with the managed data objects handled by the managed object context. Of particular significance in this diagram is the fact that although the lower levels in the stack perform a considerable amount of the work involved in providing Core Data functionality, the application code does not interact with them directly.

Before moving on to the more practical areas of working with Core Data it is important to spend some time explaining the elements that comprise the Core Data stack in a little more detail.

Managed Objects

Managed objects are the objects that are created by your application code to store data. A managed object can be thought of as a row or a record in a relational database table. For each new record to be added, a new managed object must be created to store the data. Similarly, retrieved data will be returned in the form of managed objects, one for each record matching the defined retrieval criteria. Managed objects are actually instances of the NSManagedObject class, or a subclass thereof. These objects are contained and maintained by the managed object context.


Managed Object Context

Core Data based applications never interact directly with the persistent store. Instead, the application code interacts with the managed objects contained in the managed object context layer of the Core Data stack. The context maintains the status of the objects in relation to the underlying data store and manages the relationships between managed objects defined by the managed object model. All interactions with the underlying database are held temporarily within the context until the context is instructed to save the changes, at which point the changes are passed down through the Core Data stack and written to the persistent store.

Managed Object Model

<google>ADSDAQBOX_FLOW</google> So far we have focused on the management of data objects but have not yet looked at how the data models are defined. This is the task of the Managed Object Model which defines a concept referred to as entities.

Much as a class description defines a blueprint for an object instance, entities define the data model for managed objects. In essence, an entity is analogous to the schema that defines a table in a relational database. As such, each entity has a set of attributes associated with it that define the data to be stored in managed objects derived from that entity. For example, a Contacts entity might contain name, address and phone number attributes.

In addition to attributes, entities can also contain relationships, fetched properties and fetch requests:

  • Relationships – In the context of Core Data, relationships are the same as those in other relational database systems in that they refer to how one data object relates to another. Core Data relationships can be one-to-one, one-to-many or many-to-many.
  • Fetched property – This provides an alternative to defining relationships. Fetched properties allow properties of one data object to be accessed from another data object as though a relationship had been defined between those entities. Fetched properties lack the flexibility of relationships and are referred to by Apple’s Core Data documentation as “weak, one way relationships” best suited to “loosely coupled relationships”.
  • Fetch request – A predefined query that can be referenced to retrieve data objects based on defined predicates. For example, a fetch request can be configured into an entity to retrieve all contact objects where the name field matches “John Smith”.

Persistent Store Coordinator

The persistent store coordinator is responsible for coordinating access to multiple persistent object stores. As an iPhone iOS developer you will never directly interact with the persistence store coordinator and, in fact, will very rarely need to develop an application that requires more than one persistent object store. When multiple stores are required, the coordinator presents these stores to the upper layers of the Core Data stack as a single store.

Persistent Object Store

The term persistent object store refers to the underlying storage environment in which data are stored when using Core Data. Core Data supports three disk-based and one memory-based persistent store. Disk based options consist of SQLite, XML and binary. By default, the iOS SDK will use SQLite as the persistent store. In practice, the type of store being used is transparent to you as the developer. Regardless of your choice of persistent store, your code will make the same calls to the same Core Data APIs to manage the data objects required by your application.

Defining an Entity Description

Entity descriptions may be defined from within the Xcode environment. When a new project is created with the option to include Core Data, a template file will be created named <projectname>.xcdatamodeld. Selecting this file in the Xcode project navigator panel will load the model into the entity editing environment as illustrated in the following figure:


A datamodel in Xcode 4


Create a new entity by clicking on the Add Entity button located in the bottom panel. The new entity will appear as a text box in the Entities list where a name may be typed.

To add attributes to the entity, click on the Add Attribute button located in the bottom panel. In the Attributes panel, name the attribute and specify the type and any other options that are required.

Repeat the above steps to add more attributes and additional entities.

The Xcode entity environment also allows relationships to be established between entities. Assume, for example, two entities named Contacts and Sales. In order to establish a relationship between the two tables select the Contacts entity and click on the + button beneath the Relationships panel. In the detail panel name the relationship, specify the destination as the Sales entity and any other options that are required for the relationship. Once the relationship has been established it is, perhaps, best view graphically by selecting the Table, Graph option in the Editor Style control located in the bottom panel:


A datamodel with relationship in Xcode 4


As demonstrated, Xcode makes the process of entity description creation fairly straightforward. Whilst a detailed overview of the process is beyond the scope of this book there are many other resources available that are dedicated to the subject.

Obtaining the Managed Object Context

Since many of the Core Data methods require the managed object context as an argument, the next step after defining entity descriptions often involves obtaining a reference to the context. This is achieved by first indentifying the application delegate and then calling the delegate object’s managedContextObject method:

coreDataAppDelegate *appDelegate = [[UIApplication sharedApplication] 
      delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];

Getting an Entity Description

Before managed objects can be created and manipulated in code, the corresponding entity description must first be loaded. This is achieved by calling the entityForName method of the NSEntityDescription class, passing through the name of the required entity and the context as arguments and then making a fetch request. The following code fragment obtains the description for an entity with the name Contacts:

NSEntityDescription *entityDesc = [NSEntityDescription    
     entityForName:@"Contacts" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc]; 

Creating a Managed Object

Having obtained the managed context, a new managed object conforming to a specified entity description can be created as follows by referencing the context and entity description name:

NSManagedObject *newContact;
newContact = [NSEntityDescription insertNewObjectForEntityForName:@"Contacts"   
       inManagedObjectContext:context];
NSError *error;
[context save:&error];

Getting and Setting the Attributes of a Managed Object

As previously discussed, entities and the managed objects from which they are instantiated contain data in the form of attributes. These attributes are stored in the objects using a value-key coding system, whereby the key is referenced in order to get or set the corresponding attribute. Assuming a managed object named newContact with attributes assigned the keys name, address and phone respectively, the values of these attributes may be set using the setValue method of the NSManagedObject instance:

[newContact setValue:@”John Smith” forKey:@"name"];
[newContact setValue:@”123 The Street” forKey:@"address"];
[newContact setValue:@”555-123-1234” forKey:@"phone"];

Conversely, the current value for a corresponding key may be accessed using the managed object’s valueForKey method:

NSString *contactname = [newContact valueForKey:@”name”];

The above line of code extracts the current value for the name attribute of the newContact managed object and assigns it to a string object.

Fetching Managed Objects

Once managed objects are saved into the persistent object store it is highly likely that those objects and the data they contain will need to be retrieved. Objects are retrieved by executing a fetch request and are returned in the form of an NSArray object. The following code assumes that both the context and entity description have been obtained prior to making the fetch request:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSError *error;
NSArray *matching_objects = [context executeFetchRequest:request error:&error];
[request release];

Upon execution, the matching_objects array will contain all the managed objects retrieved by the request.

Retrieving Managed Objects based on Criteria

The preceding example retrieved all of the managed objects from the persistent object store for a specified entity. More often than not only managed objects that match specified criteria are required during a retrieval operation. This is performed by defining a predicate that dictates criteria that a managed object must meet in order to be eligible for retrieval. For example, the following code implements a predicate in order to extract only those managed objects where the name attribute matches “John Smith”:

NSFetchRequest *request = [[NSFetchRequest alloc] init];

[request setEntity:entityDesc];
NSPredicate *pred = [NSPredicate predicateWithFormat:@"(name = %@)", “John Smith”];
[request setPredicate:pred];
NSError *error;
NSArray *matching_objects = [context executeFetchRequest:request error:&error]; 
[request release];

Summary

The Core Data framework stack provides a flexible alternative to directly managing data using SQLite or other data storage mechanisms. By providing an object oriented abstraction layer on top of the data the task of managing data storage is made significantly easier for the iOS iPhone application developer. Now that the basics of Core Data have been covered the next chapter entitled An iOS 4 iPhone Core Data Tutorial will work through the creation of an example application.


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book



PreviousTable of ContentsNext
An Example SQLite based iOS 4 iPhone Application (Xcode 4)An iOS 4 iPhone Core Data Tutorial (Xcode 4)