1. Suitable for quick schema
setup and modification.
2. Less memory overhead as it
uses lazy loading techniques. When you fetch data, actual objects are fetched
only when you try to access them ( aka "faulting").
3. Model Editor
Interface : You can use this cool editor interface provided inside Xcode
itself to setup schema. Create tables, setup relationships, writing queries and
much more..
4. Less code
- No need to write create
table queries.
- No need to write
programmatic fetch queries.
- Fetched data is already in
the form of model classes you need, plus you can save data using model classes
directly. So layer which performs fetching and converting data into required
model class is removed.
5. Easy to migrate to new
schema, if you have proper initial code setup then you can perform light weight
migration without writing single line of code.
6. Easy to visualise schema
using Model Editor Interface
Basics of Core Data
The learning curve for Core Data is quite large. The goal of this post is to get you up to speed with the basics of Core Data quickly by very short description and small tutorial application.
The Stack
Traditional setup :
To create database and perform any operations on it you need,
1. Schema / design for your database
2. Database connection / handle
3. Custom layer providing methods to interact with database, which performs operations to provide you data received from DB in required model format, also saves your model objects into database in required format.
Core Data setup :
Core data provides similar stack with some complex looking terms at first glance,
1. Managed Object Model
This is your schema, you can design it inside Xcode itself, Xcode provides cool interface for it.
It removes overhead of creating tables programmatically. Apart from just setting up tables and relationships it also provides many other features.
File extension for this is .xcdatamodeld.
2. Persistent Store Coordinator
This is something similar to database connection / handle.
3. Managed Object Context
Think of it as a “scratch pad” containing objects that interacts with data in persistent store. Its job is to manage objects created and returned using Core Data.
Tutorial
#Download :
#Goal :
Create simple Contact table with attributes
a. name
b. phone number
c. email
Programatically add some contacts.
Fetch added contacts and print on console.
#Steps :
0. Create single view application, all coding should be performed in ViewController.m file
1. Import Core Data Framework header
#import <CoreData/CoreData.h>
2. Declare core data stack essential properties
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
3. Copy all following methods in pragmas "Core Data Stack & Core Data Save" as it is, these are common methods required work with core data. Each method has comments for code understanding purpose.
#pragma mark - Core Data Stack
- (NSManagedObjectModel *)managedObjectModel
{
//1. Create only if nil
if (_managedObjectModel != nil)
return _managedObjectModel;
//2. Set schema file name ( .xcdatamodeld file)
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreData" withExtension:@"momd"];
//3. Initialize managedObjectModel with url
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
//1. Create only if nil
if (_persistentStoreCoordinator != nil)
return _persistentStoreCoordinator;
//2. Init with ManagedObjectModel
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
//3. Create .sqlite file path url
NSURL *documentDirPath = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *storeURL = [documentDirPath URLByAppendingPathComponent:@"CoreData.sqlite"];
//4. Add SQLLite as persistent store using .sqlite file url
NSError *error = nil;
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
NSLog(@"Failed to initialize persistent store");
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext
{
//1. Create only if nil
if (_managedObjectContext != nil)
return _managedObjectContext;
//2. Get store coordinator
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator)
return nil;
//3. Initialize managedObjectContext & set perstent store for managedObjectContext
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
#pragma mark - Core Data Save
- (void)saveContext
{
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil)
{
NSError *error = nil;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])//save only if there are changes by checking "hasChanges"
{
NSLog(@"Failed to save context data");
}
}
}
4. Setup Schema using Model Editor Interface
4a. Add new file to project
add new "Data Model" file from "Core Data" group name it as "CoreData".
IMPORTANT :
No other name will work as we have set this name in code in method managedObjectModel.
4b. This is how empty model file looks..
4c. Adding "Contact" entity and "name" attribute
4d. Use steps provided in 4c. image to add remaining attributes "email" and "phoneNumber". This is how final schema will look..
5. Create "Contact" class as subclass of NSManagedObject using Model Editor Interface
Select entity "Contact" > Go to Editor > Create NSManagedObject Subclass
This will add Contact.h & Contact.m file to project with attributes provided in schema as property names with appropriate data types.
6. Import NSManagedObject subclass "Contact" to "ViewController.m"
#import "Contact.h"
7. Copy methods addContacts and fetchContacts as it is in code..
#pragma mark - Add and Fetch Contacts
-(void)addContacts
{
//1. Get managedObjectContext
NSManagedObjectContext *context = [self managedObjectContext];
//2. Create Entity with name and context
Contact *contact1 = [NSEntityDescription
insertNewObjectForEntityForName:@"Contact"
inManagedObjectContext:context];
//3. Set attribute values
contact1.name = @"aaaa";
contact1.email = @"aaaa@aaaa.com";
contact1.phoneNumber = [NSNumber numberWithInt:1111];
Contact *contact2 = [NSEntityDescription
insertNewObjectForEntityForName:@"Contact"
inManagedObjectContext:context];
contact2.name = @"bbbb";
contact2.email = @"bbbb@bbbb.com";
contact2.phoneNumber = [NSNumber numberWithInt:2222];
Contact *contact3 = [NSEntityDescription
insertNewObjectForEntityForName:@"Contact"
inManagedObjectContext:context];
contact3.name = @"cccc";
contact3.email = @"cccc@cccc.com";
contact3.phoneNumber = [NSNumber numberWithInt:3333];
//4. Save attributes by saving context
NSError *error;
if (![context save:&error])
{
NSLog(@"Failed to save: %@", [error localizedDescription]);
}
}
-(void)fetchContacts
{
//1. Get entity by using name and context
NSManagedObjectContext *context = [self managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contact"
inManagedObjectContext:context];
//2. Create fetch request by setting entity
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
//3. Fetch objects
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
//4. Print fetched objects
for (Contact *contact in fetchedObjects)
{
NSLog(@"Name: %@", contact.name);
NSLog(@"Email: %@", contact.email);
NSLog(@"Phone: %@", contact.phoneNumber);
NSLog(@"----------------------");
}
}
8. Call methods addContacts and then fetchContacts from viewDidLoad
[self addContacts];
[self fetchContacts];
9. RUN ( Delete and Run, otherwise same contact will appear twice on second run )
10. Check console for output
/*
Expected output
2015-06-03 02:01:41.443 CoreDataTutorial[2861:26823] Name: aaaa
2015-06-03 02:01:41.443 CoreDataTutorial[2861:26823] Email: aaaa@aaaa.com
2015-06-03 02:01:41.443 CoreDataTutorial[2861:26823] Phone: 1111
2015-06-03 02:01:41.443 CoreDataTutorial[2861:26823] ----------------------
2015-06-03 02:01:41.443 CoreDataTutorial[2861:26823] Name: bbbb
2015-06-03 02:01:41.443 CoreDataTutorial[2861:26823] Email: bbbb@bbbb.com
2015-06-03 02:01:41.443 CoreDataTutorial[2861:26823] Phone: 2222
2015-06-03 02:01:41.444 CoreDataTutorial[2861:26823] ----------------------
2015-06-03 02:01:41.444 CoreDataTutorial[2861:26823] Name: cccc
2015-06-03 02:01:41.444 CoreDataTutorial[2861:26823] Email: cccc@cccc.com
2015-06-03 02:01:41.444 CoreDataTutorial[2861:26823] Phone: 3333
2015-06-03 02:01:41.444 CoreDataTutorial[2861:26823] ----------------------
*/
What should you learn next ?
As learning curve is huge, listing some pointers for important topics...
1. Relationship setup by using multiple tables (entities)
2. NSFetchResultController, Binding your data from database with some view ( showing subset of fields from DB on view ), any operation on database e.g update, add, remove etc reflects data on view automatically.
3. Using Model Editor Interface for writing queries
4. Light weight migration
5. Debugging Select the ‘Run’ scheme and select the ‘Arguments’ tab. Add the following argument: “-com.apple.CoreData.SQLDebug 1”.
6. Common errors and crash resolving
7. Working with multiple threads
8. Faulting