In simplest terms, Core Data is an object graph that can
be persisted to Disk. [...] Core Data can do a lot more for us. It serves as
the entire model layer for us. It is not just the persistence on disk, but it
is also all the objects in memory that we normally consider to be data objects.
—Marcus Zarra, Core Data
Core
data that would be it is used to store data from your iPhone application into a
sqlite file which is present in the document directory of your application.
Core data is a framework that provides you the support to make your data
objects persist in the memory. As a
programmer you are supposed to deal more with the objects and less with the sql
queries, opening the db connection, closing the db connection etc. Core data
makes you focus on that part better. You will be creating objects and core data
will take care of storing the objects in the memory. You send a fetch request
and core date will fetch those objects from the database to the main memory
back again. This is how it works.
With
the release of version 3.0, Apple has made their Core Data system available on
the iPhone OS. Core Data has been available on the Macintosh platform for a
number of years, and provides a high-level data abstraction framework that
offers integrated design tools and runtime support to address complex data
management needs unlike SQLite, the Core Data model is not strictly relational
in nature.
if
core data is used to store data for our application then why do we use SQlite,
Sqlite
is a relation db, so you can use SQL to talk to a sqlite database. You can
create tables, columns. You can create relationships between these tables etc.
So you will be having a sqlite database file and a C language API to open the
db connection, executing an SQL query and closing the db. This way you can
persist the data from your application.
Core
Data is not a relational database. Though you can go for sqlite as a store type
where core data stores the data, its not a relational database. Rather we
should not compare it with relation database. It’s an object graph persistence
system. You can user core data to persist objects on the hard drive. Some
operations are not possible with core data like Join Query, Merge query, Union
query, inner query etc.
Core Data Architecture
In
Core Data each and every entity is referred to as objects, objects that have
relationship with them. Let’s say there are two entities Parent and Child
having relationship with them then in this case Parent and Child will be
referred as objects and in Core data and you can easily manipulate them. If
your application is particularly well suited to the Relational Model, there may
be advantages to having direct SQL query access to the data storage layer. Some
of the basic classes that you must know in order to precede with core data are
given below:
ManagedObject: 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.
Persistance store
coordinator: The persistent store coordinator is
responsible for coordinating access to multiple persistent object stores. As an
iPhone 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.
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 in 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.
We
will be following some steps to make the core data application so that we don’t
mess up while using core data. We are going to work with the database having
two entities Album and Song . We will have two tables Album
and Song. Album will have two attributes name
and year. Song will have one
attribute name.
*
Create a new project , select Empty Application ( Window based Application on
XCode ). This time, check the checkbox saying, “Use core data”
Once you create project, you will see below files
You can see the CoreData framework and a CoreDataDemo.xcdatamodeld file
have been added in the project. If you observer AppDelegate.h, three properties
must have been added too.
@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
}
@property (strong, nonatomic) UIWindow *window;
@property (readonly, strong, nonatomic) NSManagedObjectContext
*managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel
*managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator
*persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
@end
|
All three are ready only. If you go to AppDelegate.m, a getter method has
been defined for all three properties. These getter methods setup the coredata
database and all the required objects that are managedObjectContext,
managedObjectModel and persistentStoreCoordinator. You can go ahead and check the AppDelegate.m
for these getter methods.
Next lets open the CoreDataDemo.xcdatamodel file. This file represents
the database schema of the database. It opens in a GUI editor into the XCode
only. We will be designing the database schema using this editor. It should
look like below.
This displays the database schema in two different editor style. You can
see an Editor style button at the bottom right.
Style 1 Style 2
Style
1 is
what it looks like in the above screenshot. We will be using this style to
actually edit the database schema. We will be adding new Entities ( Tables ) ,
attributes (columns) to an Entity . We will be adding the relationships in two
Entities etc.
Style
2 will
displays the graphical representation of the schema. Once done designing the
schema in the first style, you can verify that in the second style visually.
Style 2 looks like as the screen shot below.
Ok, lets switch to the style 1 and start designing the database schema.
You will see left pane with three sections Entites,
Fetch Requests and Configurations.
Click on “Add Entity” button at the bottom. This will add the entity.
Name it Album. Then add the
attributes to the Album table in the Attributes section on the right.
Same way, add Song Entity and add an attribute “name” in the Song table.
Next we need to add relationships in these two entities. Select the Album entity and add a relation
ship there. Give it a name albumToSong. Set the Destination as “Song”.
In the details view on the right side, we need to set some more
properties. Check the “To-Many Relationship” checkmark. This how we can specify
that Album to Song is one-to-many relationship. An Album can have multiple
songs.
There are some
other advanced options that you can set as well eg. You may set the Delete
Rule to Cascade if you want.
Next add a
relationship to the Song Entity. Name it
“songToAlbum”. You can simply make it the inverse of “albumToSong” by
selecting it into the last drop down list. It should then look like below.
You can visually
verify the design by changing the editor style to style 2. It should look like
below.
That’s it, we are
done with the design of the database schema. Its time to create the
NSManagedObject classes for Album and Song entities.
Select these two
entities and right click on resources section. Click on “Add New file” option.
Navigate to CoreData section over there and select the NSManagedObject
subclass. Click next and on the next page click create. This will add two
classes to the project that are Album and Song.
The resources should have two more classes now.
If you check out the classes, every class has go the needed method. Like
Album should have a methods like
- (void)addAlbumToSongObject:(Song *)value;
-
(void)removeAlbumToSongObject:(Song *)value;
-
(void)addAlbumToSong:(NSSet *)values;
-
(void)removeAlbumToSong:(NSSet *)values;
Same goes for Song. All the required methods must have been added to the
Song class as well. Now its time to go the AppDelegate and perform some
operations like inserting objects to and reading objects from the database.
Go to AppDelegate.m
and write a method insertData as below. insertData will insert some objects in
to the database
-(void)insertData
{
Album * alb1 = [NSEntityDescription insertNewObjectForEntityForName:@"Album" inManagedObjectContext:self.managedObjectContext];
alb1.name = @"Rockstar";
alb1.year = [NSNumber numberWithInt:2011];
Song * s1 = [NSEntityDescription insertNewObjectForEntityForName:@"Song" inManagedObjectContext:self.managedObjectContext];
s1.name = @"Sadda
haq";
Song * s2 = [NSEntityDescription insertNewObjectForEntityForName:@"Song" inManagedObjectContext:self.managedObjectContext];
s2.name = @"Jo
Bhi Main";
Album * alb2 = [NSEntityDescription insertNewObjectForEntityForName:@"Album" inManagedObjectContext:self.managedObjectContext];
alb2.name = @"Nirvana";
alb2.year = [NSNumber numberWithInt:1988];
Song * s3 = [NSEntityDescription insertNewObjectForEntityForName:@"Song" inManagedObjectContext:self.managedObjectContext];
s3.name = @"Come
as You are";
Song * s4 = [NSEntityDescription insertNewObjectForEntityForName:@"Song" inManagedObjectContext:self.managedObjectContext];
s4.name = @"The
man who sold The World";
[alb1 addAlbumToSongObject:s1];
[alb1 addAlbumToSongObject:s2];
[alb2 addAlbumToSongObject:s3];
[alb2 addAlbumToSongObject:s4];
[self.managedObjectContext save:nil];
}
|
In the above method, we are creating two Album objects alb1 and alb2.
There are four Song objects s1,s2,s3 and
s4. After that we add song objects to the corresponding album objects.
Finally we save the context. Till this line all objects are created in the context.
In order to save the objects into database, you need to call save method on the
context object. Lets call this method
from didFinishLaunching as below.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary
*)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
[self insertData];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
|
Run the App and it
will insert the data into the database. Next we write a readData method that
will read the data from the database.
-(void)readData
{
NSFetchRequest * req = [[NSFetchRequest alloc]init];
[req setEntity:[NSEntityDescription entityForName:@"Album" inManagedObjectContext:self.managedObjectContext]];
NSArray * result =
[self.managedObjectContext executeFetchRequest:req error:nil];
for (Album * alb in result)
{
NSLog(@"Album
Name : %@",alb.name);
NSLog(@"Album
Year : %@",alb.year);
for( Song * sng in alb.albumToSong )
{
NSLog(@" Song Name : %@",sng.name);
}
}
}
|
NSFetchRequest : This class is used
to create query objects.
We create fetch
request, then set the Entity to Album. This is going to be simple “ select *
from Album” query. After that we execute the fetch request on the context
object. Context executes the fetch request and returns the result. The result
of the query is going to be an array of Album objects. So we catch it in an
array called “result”. After that we iterate through the “result” array and
print the Album objects. When we get an album object we can access the
“albumToSong” property of it to access all the song objects for this album.
This property is of type NSSet because an album can have multiple songs as per
the one-to-many relationship. We then iterate over all the songs for an album
and print those as well. Lets give a
call to the readData method from didFinishLaunching and comment the insertData
call.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary
*)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// [self
insertData];
[self readData];
self.window.backgroundColor
= [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
|
Run the App and you
should see the below output on the Console.