Tuesday, April 2, 2013

CoreData in iPhone Complete Tutorial (Basic)

Hola,, iDevelopers,, RDC is here

Enjoying Punjabi Pop "Sadi Gali Aaja Sanu.." and I am going to write one more Article
about one of the important key feature in iOS.

Because Now-days Core Data is widely using in iPhone Applications
Shortly I'll post complete theory article on Core Data here

How to use Core Data in our iPhone application with Insert, Select, Search and Delete operation programmatically?



So stay with me, and do it step by step by .. don't forget to drop me a message or comment.

At the end of this Tutorial you can find Complete Source code zip file.

Before starting You may like to know our Database details

 -----------------------------------------------------
| CoreData Model Name : contacts.momd           |
| CoreData Database File Name : contacts.sqlite |
| CoreData Entity(Table) Name : Contacts        |
|       Table Columns Name : NAME, ADDRESS, PHONE     |
 -----------------------------------------------------


Note : This Application Developed Using : iOS 6 , Xcode 4.6, and MAC OS X Lion 10.8.1

PHASE - I (Create New Project)

So, Let's Fire Xcode!!

Go to File --> New --> Project

Now we can see a Pop up Window for selecting our application templet 

So make sure you select Application in iOS option on your Left hand side.
then select Single View Application as shown in below picture and Go for Next..



In the Next Window we need to put Our Project Details this way

------------------------------------------------------------
| Product Name : CoreDataDemo |
| Organization Name :RDCWorld |
| Company Identifier : com.rdcworld         |
|                         |
| Class Prefix :  (leave it blank for now) |
|                         |
| Devices : iPhone                 |
------------------------------------------------------------

Note : Don't forget to Make Tick mark on "Use Automatic Reference Counting" option.



Go to Next --> Create.

Now you can see Xcode default dashboard with our newly created project .

PHASE - II (Add Extra Frameworks/ Lib and Create required Files)

to use the Core Data we need to add CoreData.framework to our Project.
procedure is simple just follow the below steps..

1. select Project (Blue Icon) go to --> Build Phased --> Link Binary With Libraries option --> click (+) and you will get popup window, so search for "coredata", -->select CoreData.framework --> click to add.



after adding successful you can see CoreData.framework added to our project, drag it to the Frameworks folder.

PHASE - III (Import CoreData header file in .pch)

~ ~ ~ ~ ~ ~ ~ ~ ~           Update .pch file  (CoreDataDemo-Prefix.pch)          ~ ~ ~ ~ ~ ~ ~ ~ ~ 

here I would like to suggest you, when we need any lib/framework classes in our application's class then we need to import particular relevant header file, but if we will import in .pch file then it will be available in whole application.

1. Open CoreDataDemo-Prefix.pch file in folder named "Supporting Files" in default project structure.
2. Here we can see by default already to classes added (UIKit and Foundation), below to these two file just add core data header file this way

#import <CoreData/CoreData.h>

So Finally our CoreDataDemo-Prefix.pch file look like

-----------------------------------------------------------------------------------------------------------------------------------------
//
// Prefix header for all source files of the 'CoreDataDemo' target in the 'CoreDataDemo' project
//

#import <Availability.h>

#ifndef __IPHONE_4_0
#warning "This project uses features only available in iOS SDK 4.0 and later."
#endif

#ifdef __OBJC__
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
#endif
-----------------------------------------------------------------------------------------------------------------------------------------
Good!! now save it and go ahead -->

PHASE - IV (Create Core Data model file to store entity)

Now We will Create one  "contacts.xcdatamodeld" file

1. Right click on project (as shown in picture) --> New File 



2. Select Data Model Template (in iOS + Core Data option) --> Go Next



3. Give the name as "Contacts" --> Create



Now we can see contacts.xcdatamodeld  file is added to our project.

Create Entity, Attributes in contacts.xcdatamodeld file

Create Entity

1. Open Contacts.xcdatamodeld file, we can see blank database schema graph here and no entity so far.



2. Click on Add Entity (+) button (it's on Bottom Left side) to create new entity-->Give the name "Contacts"



Create Attributes

3. select Entity (Contacts) --> Click on Add Attribute (+) button (it's on Bottom Right side) to create new attribute-->double click on it, change Attribute = name and Type = string

4. do the same and create two more attribute phone and address.



Good!! save the file.

PHASE - V (Create Object Model class for Entity )

~ ~ ~ ~ ~ ~ ~ ~ ~              Object Model Class (Contacts)          ~ ~ ~ ~ ~ ~ ~ ~ ~ 

Now We will create model class for this entity "Contacts"

1. Right click on project  --> New File

2. Select NSManagedObjectsubclass Template (in iOS + Core Data option) --> Go Next



3. select the entity Contacts  and go to Next.



Now we can see contacts.h and contacts.m  files are added to our project.

So Finally our Contacts.h file look like

-----------------------------------------------------------------------------------------------------------------------------------------
//
//  Contacts.h
//  CoreDataDemo
//
//  Created by RDC on 29/03/13.
//  Copyright (c) 2013 RDC World. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>


@interface Contacts : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSString * phone;
@property (nonatomic, retain) NSString * address;

@end
-----------------------------------------------------------------------------------------------------------------------------------------

also Finally our Contacts.m file look like

-----------------------------------------------------------------------------------------------------------------------------------------
//
//  Contacts.m
//  CoreDataDemo
//
//  Created by RDC on 29/03/13.
//  Copyright (c) 2013 RDC World. All rights reserved.
//

#import "Contacts.h"


@implementation Contacts

@dynamic name;
@dynamic phone;
@dynamic address;

@end
-----------------------------------------------------------------------------------------------------------------------------------------

PHASE - V (Create Helper Class to handle all the Core Data Tasks )

~ ~ ~ ~ ~ ~ ~ ~ ~              HELPER Class (CoreDataHelper)          ~ ~ ~ ~ ~ ~ ~ ~ ~  

Now We will create two Important Classes 

Here is the Heart of Application

We will create Helper class for Core Data
CoreDataHelper.h
CoreDataHelper.m

Where we will mange complete core data life cycle, also we are going to add method for making various operation on Core Data
such as INSERT, SEARCH,DELETE,VIEW ALL etc.

So stay tune and try to get the rhythm of this music … oops!! it would be Core data :)

Let's follow to the footprints..

1. Right click on project  --> New File

2. Select Objective-C class Template (in iOS + Cocoa Touch) --> Go Next



3. put the details as given below

Class = CoreDataHelper
Subclass of = NSObject

 and go to Next.



Now we can see CoreDataHelper.h and CoreDataHelper.m  files are added to our project.

So, this time our project structure is look like 



Note : You may have question here As I have put all the files in MVC manner, 
If you wish to do that, please! right click on project and create New Groups and give name as Models, Views, Controllers,CoreData Helper.
then just drag the files in relative folder groups as shown in screen shot.


4. open CoreDataHelper.h  

5. add three most important instance variables with @property of Core Data classes

@property (nonatomic,retain) NSManagedObjectContext *context;
@property (nonatomic, retain) NSManagedObjectModel *objectModel;
@property (nonatomic, retain) NSPersistentStoreCoordinator *coordinator;

6. declare static init method to initialise the Helper class

+(CoreDataHelper *) initCoreDataHelper;

7. declare all the require instance method to manage Core Data life cycle.

-(void) initializeContext;
-(NSString *) getApplicationDocumentsDirectoryPath;
-(NSManagedObjectModel *) initilizeManagedObjectModel;
-(NSPersistentStoreCoordinator *) initilizeManagedPersistentStoreCoordinator;
-(void) saveCurrentContext;

8. and finally declare method to handle all Core Data operations like Insert and Delete data.

/methods to perform database operations
-(void) insertContactInfoName :(NSString *)name Address:(NSString *)address PhoneNo:(NSString *)phoneNO;
-(void) selectAllContacts;
-(NSManagedObject *) searchContactInfoByName :(NSString *) name;
-(void) deleteContactInfoByName:(NSString *) name;

So Finally our CoreDataHelper.h file look like
-----------------------------------------------------------------------------------------------------------------------------------------
//
//  CoreDataHelper.h
//  CoreDataDemo
//
//  Created by RDC on 01/04/13.
//  Copyright (c) 2013 RDC World. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@interface CoreDataHelper : NSObject

@property (nonatomic,retain) NSManagedObjectContext *context;
@property (nonatomic, retain) NSManagedObjectModel *objectModel;
@property (nonatomic, retain) NSPersistentStoreCoordinator *coordinator;

//mehthods to manage core data life cycle
+(CoreDataHelper *) initCoreDataHelper;
-(void) initializeContext;
-(NSString *) getApplicationDocumentsDirectoryPath;
-(NSManagedObjectModel *) initilizeManagedObjectModel;
-(NSPersistentStoreCoordinator *) initilizeManagedPersistentStoreCoordinator;
-(void) saveCurrentContext;

//methods to perform database operations
-(void) insertContactInfoName :(NSString *)name Address:(NSString *)address PhoneNo:(NSString *)phoneNO;
-(void) selectAllContacts;
-(NSManagedObject *) searchContactInfoByName :(NSString *) name;
-(void) deleteContactInfoByName:(NSString *) name;

@end
-----------------------------------------------------------------------------------------------------------------------------------------

Great going!! just save the file and move to it's implementation file 

9. open CoreDataHelper.m file 

10.  add @synthesize (for all declared variable in header file with @property) just below to @implementation 

@synthesize context;
@synthesize objectModel;
@synthesize coordinator;

11. create static instance of CoreDataHelper class.

static CoreDataHelper *coreDataHelper;

12. update the initCoreDataHelper method to initialise this class and Current Context.

+(CoreDataHelper *) initCoreDataHelper{  
    
    if (coreDataHelper == nil) { 
        coreDataHelper = [[CoreDataHelper alloc] init];        
        [coreDataHelper initializeContext];        
    }
    return coreDataHelper;    
}

See don't worry we are going to provide the body for "initializeContext" method, used here

13. now update the getApplicationDocumentsDirectoryPath method's body to get path

-(NSString *) getApplicationDocumentsDirectoryPath{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
    return basePath;
}

14. update initilizeManagedObjectModel to init the managed object model

- (NSManagedObjectModel *) initilizeManagedObjectModel{
    if (objectModel != nil) {
        return objectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Contacts" withExtension:@"momd"];
    objectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        
    return objectModel;
}

15. here is time to create database using all gathered info.
so provide the body for initilizeManagedPersistentStoreCoordinator method

-(NSPersistentStoreCoordinator *) initilizeManagedPersistentStoreCoordinator{         
    if (coordinator != nil) {
        return coordinator;
    }    
    NSURL *storeUrl = [NSURL fileURLWithPath:[[self getApplicationDocumentsDirectoryPath]stringByAppendingPathComponent: @"Contacts.sqlite"]];       
    NSError *error = nil;
    coordinator = [[NSPersistentStoreCoordinator alloc]
                                  initWithManagedObjectModel:[self initilizeManagedObjectModel]];
    if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                  configuration:nil URL:storeUrl options:nil error:&error]) {        
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    return coordinator;
}

16. yeah! as I promised now update the body for initializeContext method here, to init the current context of core data

-(void) initializeContext{    
    if (context == nil) {        
        NSPersistentStoreCoordinator *acoordinator = [self initilizeManagedPersistentStoreCoordinator];
        context = [[NSManagedObjectContext alloc] init];
        [context setPersistentStoreCoordinator:acoordinator];        
    } 
}

17. final method for Core Data life cycle to save the current context when app is going to… hell .. 
Okay!! This method we will use in App Delegate class to store our application core data state when user quite app etc.

-(void) saveCurrentContext{
    NSError *error = nil;
    if (context != nil) {
        if ([context hasChanges] && ![context save:&error]) {            
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }
}

//now update the methods to perform database operations

18. here we have Four method to hand INSERT, SELECT ALL, SEARCH, DELETE operations on Core Data


All below steps we need to follow to work with Core Data so keep in mind these things

 --------------------------------------------------------------------------------------
|               Get Current Context (NSManagedObjectContext)           |
|               Init Fetch Request (optional)                                             |
|               Get Entity Description                                             |
|               Add Entity Description to Request                                     |
|               Create Predicate (Optional)                                                   |
|               Add Predicate to Request                                                     |
|               Execute Fetch Request                                                           |
|               Use Results                                                                               |
|               Save Context (optional)                                                         |
---------------------------------------------------------------------------------------


18.1 Insert contact method

-(void) insertContactInfoName:(NSString *)name Address:(NSString *)address PhoneNo:(NSString *)phoneNO{     
       
    NSManagedObject *newContact;   
    newContact = [NSEntityDescription insertNewObjectForEntityForName:@"Contacts" inManagedObjectContext:context];
    [newContact setValue:name forKey:@"name"];
    [newContact setValue:address forKey:@"address"];
    [newContact setValue:phoneNO forKey:@"phone"];
    NSError *error = nil;
    if ([context save:&error]) {
        NSLog(@"Contact saved");
    }
    else{
        NSLog(@"Error occured while saving");
    }    
}

18.2  select all the stored contact method

-(void) selectAllContacts{       
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];
    
    NSError *error = nil;
    NSArray *objects = [context executeFetchRequest:fetchRequest error:&error];    
    if ([objects count]>0) {        
        for (NSManagedObject *aContact in objects) {
            NSLog(@"name=%@, address=%@, phone=%@",[aContact valueForKey:@"name"],[aContact valueForKey:@"address"],[aContact valueForKey:@"phone"]);
        }
    }
    else{        
        NSLog(@"no matches found");                
    }      
}

18.3 search particular contact info by Name and returns object

-(NSManagedObject *) searchContactInfoByName:(NSString *)name{   
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];
    
    //add predicate to search by name
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@",name];   
    [fetchRequest setPredicate:predicate];
    NSManagedObject *aContact = nil;
    
    NSError *error;
    NSArray *objects = [context executeFetchRequest:fetchRequest error:&error];
    
    if ([objects count]==0) {
        NSLog(@"no matches found");
    }
    else{
        aContact = [objects objectAtIndex:0];
        NSLog(@"name=%@, address=%@, phone=%@",[aContact valueForKey:@"name"], [aContact valueForKey:@"address"],[aContact valueForKey:@"phone"]);       
    }        
    return aContact;
}


18.4 delete particulate contact by Name

-(void) deleteContactInfoByName:(NSString *)name{    
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:context];    
    [fetchRequest setEntity:entity];    
    
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", name];
    NSLog(@"my del predicate is :%@",predicate);
    [fetchRequest setPredicate:predicate];
    
    NSError *error = nil;
    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];     
    
    if ([fetchedObjects count] >0) {
        //delete object
        NSManagedObject *aContactObject= [fetchedObjects objectAtIndex:0];
        [context deleteObject:aContactObject];
        
        // Save everything after deletion
        if ([context save:&error]) {
            NSLog(@"The update was successful!");
        } else {
            NSLog(@"The update wasn't successful: %@", [error localizedDescription]);
        }
    }
    else{
        NSLog(@"no matches found");
    }    
}

These useful methods we can reuse anywhere in our app just by passing params

Note : I add #pragma mark the to make more clear and formatted coding style and easy to find any stuff in file.
shortly I am going to write one article on #pragma mark, how to use them in iOS? also what are advantages?

So Finally our CoreDataHelper.m file look like
-----------------------------------------------------------------------------------------------------------------------------------------
//
//  CoreDataHelper.m
//  CoreDataDemo
//
//  Created by RDC on 01/04/13.
//  Copyright (c) 2013 RDC World. All rights reserved.
//

#import "CoreDataHelper.h"

@implementation CoreDataHelper
@synthesize context;
@synthesize objectModel;
@synthesize coordinator;

#pragma mark - COREDATA -INITILIZE

static CoreDataHelper *coreDataHelper;

+(CoreDataHelper *) initCoreDataHelper{  
    
    if (coreDataHelper == nil) { 
        coreDataHelper = [[CoreDataHelper alloc] init];        
        [coreDataHelper initializeContext];        
    }
    return coreDataHelper;    
}

#pragma mark - COREDATA -MANAGE LIFE CYCLE

//1. to get the dir path where we store our database file
-(NSString *) getApplicationDocumentsDirectoryPath{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
    return basePath;
}

// 2. to manage object model
- (NSManagedObjectModel *) initilizeManagedObjectModel{
    if (objectModel != nil) {
        return objectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Contacts" withExtension:@"momd"];
    objectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];        
    return objectModel;
}

// 3.to create core data 
-(NSPersistentStoreCoordinator *) initilizeManagedPersistentStoreCoordinator{         
    if (coordinator != nil) {
        return coordinator;
    }    
    NSURL *storeUrl = [NSURL fileURLWithPath:[[self getApplicationDocumentsDirectoryPath]stringByAppendingPathComponent: @"Contacts.sqlite"]];       
    NSError *error = nil;
    coordinator = [[NSPersistentStoreCoordinator alloc]
                                  initWithManagedObjectModel:[self initilizeManagedObjectModel]];
    if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                  configuration:nil URL:storeUrl options:nil error:&error]) {        
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    return coordinator;
}

//4. to manage object context 
-(void) initializeContext{    
    if (context == nil) {        
        NSPersistentStoreCoordinator *acoordinator = [self initilizeManagedPersistentStoreCoordinator];
        context = [[NSManagedObjectContext alloc] init];
        [context setPersistentStoreCoordinator:acoordinator];        
    } 
}

//5. to save context when app is going to be close/quit
-(void) saveCurrentContext{
    NSError *error = nil;
    if (context != nil) {
        if ([context hasChanges] && ![context save:&error]) {            
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }
}


#pragma mark - COREDATA -INSERT

-(void) insertContactInfoName:(NSString *)name Address:(NSString *)address PhoneNo:(NSString *)phoneNO{     
       
    NSManagedObject *newContact;   
    newContact = [NSEntityDescription insertNewObjectForEntityForName:@"Contacts" inManagedObjectContext:context];
    [newContact setValue:name forKey:@"name"];
    [newContact setValue:address forKey:@"address"];
    [newContact setValue:phoneNO forKey:@"phone"];
    NSError *error = nil;
    if ([context save:&error]) {
        NSLog(@"Contact saved");
    }
    else{
        NSLog(@"Error occured while saving");
    }    
}

#pragma mark - COREDATA -SELECT / VIEW ALL DATA

-(void) selectAllContacts{       
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];
    
    NSError *error = nil;
    NSArray *objects = [context executeFetchRequest:fetchRequest error:&error];    
    if ([objects count]>0) {        
        for (NSManagedObject *aContact in objects) {
            NSLog(@"name=%@, address=%@, phone=%@",[aContact valueForKey:@"name"],[aContact valueForKey:@"address"],[aContact valueForKey:@"phone"]);
        }
    }
    else{        
        NSLog(@"no matches found");                
    }      
}

#pragma mark - COREDATA - SEARCH

//this method will returns an Object which contains one person's Contact info details
-(NSManagedObject *) searchContactInfoByName:(NSString *)name{   
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];
    
    //add predicate to search by name
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@",name];   
    [fetchRequest setPredicate:predicate];
    NSManagedObject *aContact = nil;
    
    NSError *error;
    NSArray *objects = [context executeFetchRequest:fetchRequest error:&error];
    
    if ([objects count]==0) {
        NSLog(@"no matches found");
    }
    else{
        aContact = [objects objectAtIndex:0];
        NSLog(@"name=%@, address=%@, phone=%@",[aContact valueForKey:@"name"], [aContact valueForKey:@"address"],[aContact valueForKey:@"phone"]);       
    }        
    return aContact;
}

#pragma mark - COREDATA - DELETE

-(void) deleteContactInfoByName:(NSString *)name{    
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:context];    
    [fetchRequest setEntity:entity];    
    
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", name];
    NSLog(@"my del predicate is :%@",predicate);
    [fetchRequest setPredicate:predicate];
    
    NSError *error = nil;
    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];     
    
    if ([fetchedObjects count] >0) {
        //delete object
        NSManagedObject *aContactObject= [fetchedObjects objectAtIndex:0];
        [context deleteObject:aContactObject];
        
        // Save everything after deletion
        if ([context save:&error]) {
            NSLog(@"The update was successful!");
        } else {
            NSLog(@"The update wasn't successful: %@", [error localizedDescription]);
        }
    }
    else{
        NSLog(@"no matches found");
    }    
}
@end
-----------------------------------------------------------------------------------------------------------------------------------------

Bravo!! Bravo!!.. keep moving like a RockStar \m/

PHASE - VI (Design UI)

We need to add  some UITextFields, UIButtons,UILabel and Title Bar on our screen to get it work.

So, Just open ViewController.xib file you can see default blank layout

1. Let's drag UINavigationBar from Object library double click on it and give title as  "Core Data : Contact Info", (we will use this for just showing app Title)

2. TextFields : 
2.1 now drag TextFields for Taking input Name ,adjust full width, then go to Attribute Inspector and update Placeholder value as "enter name here" 

2.2 do same for next TextField for Taking input Address and change its Placeholder value as "enter address here" 

2.3. drag one more TextField for Taking input Phone No and change its Placeholder value as "enter 10 digit phone no" 

3. UILabel : drag one label and double click on it, change text as "Note : for search and delete only enter name"

4. UIButtons: drag 4 Buttons and double click and give them name as Save, View All, Search, and Delete respectively .

Now adjust all these items on your Layout as per shown in below screen shot.



PHASE - VII (Create IBOutlets and IBAction )

We are going to create IBOutlet for UITextFields and IBAction methods for UIButtons .
So just open ViewController.xib 

Okay, Now select Assistant Editor on Top Right side



You can see our ViewController.xib (Left side) + ViewController.h (Right side) opened together.
1. Create IBOutlets

1.1 Select UITextField (which says - 'enter name here') --> Right Click on it 

1.2 Click on "New Referencing outlet" option and drag cursor to ViewController.h(right side) file, when your cursor is between @interface and @end you can see like this.



1.3 Now you will get Popup Window 

just put Name : "nameTextField" and click on Connect.



you can see below line added in our ViewController's header file

@property (weak, nonatomic) IBOutlet UITextField *nameTextField;

1.4 do the same for next two TextFields and give them name as "addressTextField" and "phoneNoTextField" respectively 

this time you can see two IBOutlets created in header file

@property (weak, nonatomic) IBOutlet UITextField *addressTextField;
@property (weak, nonatomic) IBOutlet UITextField *phoneNoTextField;


2. Create IBAction methods
2.1 Select UIButton (which says -'Save') --> Right Click on it 

2.2 Click on Touchup Inside in  "Sent Events" option and drag cursor just below to new created IBOutlets, and put the method name "" in pop window



you can see new method is added in our ViewController's header file

- (IBAction)saveContactInfo:(id)sender;

2.3 do the same for next three Buttons and give methods name as "viewAllContactsInfo","searchContactInfo" and "deleteContactInfo" respectively.

this time you can see three new  IBAction methods created in header file

- (IBAction)viewAllContactsInfo:(id)sender;
- (IBAction)searchContactInfo:(id)sender;
- (IBAction)deleteContactInfo:(id)sender;

Done!! now back to Standard Editor




PHASE - VIII (Hook Up Delegate with File Owner to Handle Keypad Go )

Here we need to hook up our TextFields Delegate to File Owner, so we can use its method to hand Keypad.
when use Tap Return key while typing then keypad should go back.

1. Open ViewController.xib

2. Select UITextField (which says - 'enter name here') --> go the Connection Inspector --> drag cursor from Delegate to File owner (Right to Left)
as shown in below screen shot



3. repeat same for next two Text Fields (Address, Phone No)

Note : you can achieve same by doing it programmatically in ViewController's viewDidLoad method.

nameTextField.delegate =self;
addressTextField.delegate=self;
phoneNoTextField.delegate=self;


~ ~ ~ ~ ~ ~ ~ ~ ~              Controller Class (ViewController)          ~ ~ ~ ~ ~ ~ ~ ~ ~  

We are about to Accomplish our goal, So, stay tune with RDC.

This time we use all the hard-work we have done in Model or Helper classes.

Open ViewController.h file

1. we need to use Model class instance hence add @class for that

@class Contacts;

2. add protocol UITextFieldDelegate because we will enable Keypad Go back when user hit Return Key on any TextFiled

@interface ViewController : UIViewController<UITextFieldDelegate>

2. You can see some IBOutlets and IBActions methods we already Added By Xcode, we did it From UI.

3. declare property for our Model class instance

@property (nonatomic, retain) Contacts  *aContact;

4. declare property of TextField class instance, we will use this, for which TextFiled is active for sending keypad back.

@property (nonatomic, retain) UITextField *active_text;

Good! save this File.


So Finally our ViewController.h file look like

-----------------------------------------------------------------------------------------------------------------------------------------
//
//  ViewController.h
//  CoreDataDemo
//
//  Created by RDC on 29/03/13.
//  Copyright (c) 2013 RDC World. All rights reserved.
//

#import <UIKit/UIKit.h>

@class Contacts;    

@interface ViewController : UIViewController <UITextFieldDelegate>

@property (weak, nonatomic) IBOutlet UITextField *nameTextField;
@property (weak, nonatomic) IBOutlet UITextField *addressTextField;
@property (weak, nonatomic) IBOutlet UITextField *phoneNoTextField;

- (IBAction)saveContactInfo:(id)sender;
- (IBAction)viewAllContactsInfo:(id)sender;
- (IBAction)searchContactInfo:(id)sender;
- (IBAction)deleteContactInfo:(id)sender;

@property (nonatomic, retain) Contacts  *aContact;
@property (nonatomic, retain) UITextField *active_text;

@end
-----------------------------------------------------------------------------------------------------------------------------------------


Now come to ViewController.m file , open it

1. add #import statement for Model class and CoreDataHelper, we are going to use them in this 

#import "CoreDataHelper.h"
#import "Contacts.h"

2. add synthesize (for all declared variable in header file with @property) just below to @implementation

@synthesize nameTextField;
@synthesize addressTextField;
@synthesize phoneNoTextField;
@synthesize active_text;
@synthesize aContact;

2. update the body of saveContactInfo method

- (IBAction)saveContactInfo:(id)sender {     
    NSString *name = nameTextField.text;
    NSString *address = addressTextField.text;
    NSString *phone = phoneNoTextField.text;
    
    if ([name length] >1 && [address length]>1 && [phone length]>1) {        
        [[CoreDataHelper initCoreDataHelper] insertContactInfoName:name Address:address PhoneNo:phone];        
        nameTextField.text =@"";
        addressTextField.text=@"";
        phoneNoTextField.text=@"";
    }
    else{
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
                                                        message:@"please! enter text" delegate:self
                                              cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alert show];
    }
}

3. update the body of viewAllContactsInfo method

- (IBAction)viewAllContactsInfo:(id)sender {    
    //the result contacts we have printed on log in Helper class itself
    [[CoreDataHelper initCoreDataHelper] selectAllContacts];
}

4. update the body of searchContactInfo method

- (IBAction)searchContactInfo:(id)sender {    
    NSString *name = nameTextField.text;    
    if ([name length] >1) {
        
        NSManagedObject *aContactObject =[[CoreDataHelper initCoreDataHelper] searchContactInfoByName:name];
        
        NSString *name = [aContactObject valueForKey:@"name"];
        NSString *address = [aContactObject valueForKey:@"address"];
        NSString *phone = [aContactObject valueForKey:@"phone"];
        
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Search Result"
                                                        message:[NSString stringWithFormat:@"We found Name : %@, Address : %@, Phone No : %@",name,address,phone]
                                                       delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alert show];        
        nameTextField.text =@"";
        addressTextField.text=@"";
        phoneNoTextField.text=@"";
    }
    else{
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
                                                        message:@"please! enter text" delegate:self cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil, nil];
        [alert show];
    }
}

5. update the body of deleteContactInfo method

- (IBAction)deleteContactInfo:(id)sender {    
    if ([nameTextField.text length] >1 ) {        
        [[CoreDataHelper initCoreDataHelper] deleteContactInfoByName:nameTextField.text];        
        nameTextField.text =@"";
        addressTextField.text=@"";
        phoneNoTextField.text=@"";
    }
    else{
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"please! enter text"
                                                       delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alert show];
    }
}

6. now we will implement UITextFiled's Delegate method to handle Keypad Go Back when user Hit Return key

-(void)textFieldDidBeginEditing:(UITextField *)textField{    
    self.active_text = textField;
}

-(BOOL)textFieldShouldReturn:(UITextField *)textField{    
    [textField resignFirstResponder];
    return TRUE;
}



So Finally our ViewController.m file look like

-----------------------------------------------------------------------------------------------------------------------------------------
//
//  ViewController.m
//  CoreDataDemo
//
//  Created by RDC on 29/03/13.
//  Copyright (c) 2013 RDC World. All rights reserved.
//

#import "ViewController.h"
#import "CoreDataHelper.h"
#import "Contacts.h"

@interface ViewController ()

@end

@implementation ViewController
@synthesize nameTextField;
@synthesize addressTextField;
@synthesize phoneNoTextField;
@synthesize active_text;
@synthesize aContact;

#pragma mark - ViewController Life Cycle Methods

- (void)viewDidLoad{
    [super viewDidLoad];
}

- (void)didReceiveMemoryWarning{
    [super didReceiveMemoryWarning];    
}

#pragma mark - Button click methods

- (IBAction)saveContactInfo:(id)sender {     
    NSString *name = nameTextField.text;
    NSString *address = addressTextField.text;
    NSString *phone = phoneNoTextField.text;
    
    if ([name length] >1 && [address length]>1 && [phone length]>1) {        
        [[CoreDataHelper initCoreDataHelper] insertContactInfoName:name Address:address PhoneNo:phone];        
        nameTextField.text =@"";
        addressTextField.text=@"";
        phoneNoTextField.text=@"";
    }
    else{
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
                                                        message:@"please! enter text" delegate:self
                                              cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alert show];
    }
}

- (IBAction)viewAllContactsInfo:(id)sender {    
    //the result contacts we have printed on log in Helper class itself
    [[CoreDataHelper initCoreDataHelper] selectAllContacts];
}

- (IBAction)searchContactInfo:(id)sender {    
    NSString *name = nameTextField.text;    
    if ([name length] >1) {
        
        NSManagedObject *aContactObject =[[CoreDataHelper initCoreDataHelper] searchContactInfoByName:name];
        
        NSString *name = [aContactObject valueForKey:@"name"];
        NSString *address = [aContactObject valueForKey:@"address"];
        NSString *phone = [aContactObject valueForKey:@"phone"];
        
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Search Result"
                                                        message:[NSString stringWithFormat:@"We found Name : %@, Address : %@, Phone No : %@",name,address,phone]
                                                       delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alert show];        
        nameTextField.text =@"";
        addressTextField.text=@"";
        phoneNoTextField.text=@"";
    }
    else{
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
                                                        message:@"please! enter text" delegate:self cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil, nil];
        [alert show];
    }
}

- (IBAction)deleteContactInfo:(id)sender {    
    if ([nameTextField.text length] >1 ) {        
        [[CoreDataHelper initCoreDataHelper] deleteContactInfoByName:nameTextField.text];        
        nameTextField.text =@"";
        addressTextField.text=@"";
        phoneNoTextField.text=@"";
    }
    else{
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"please! enter text"
                                                       delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
        [alert show];
    }
}

#pragma mark - UITextField Delegate methods for Keypad Return key

-(void)textFieldDidBeginEditing:(UITextField *)textField{
    self.active_text = textField;
}

-(BOOL)textFieldShouldReturn:(UITextField *)textField{    
    [textField resignFirstResponder];
    return TRUE;
}
@end
-----------------------------------------------------------------------------------------------------------------------------------------

~ ~ ~ ~ ~ ~ ~ ~ ~              Application Delegate Class (AppDelegate)          ~ ~ ~ ~ ~ ~ ~ ~ ~  


Make sure your AppDelegate file code should be default 

Finally our AppDelegate.h file look like 

-----------------------------------------------------------------------------------------------------------------------------------------
//
//  AppDelegate.h
//  CoreDataDemo
//
//  Created by RDC on 29/03/13.
//  Copyright (c) 2013 RDC World. All rights reserved.
//

#import <UIKit/UIKit.h>

@class ViewController;

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) ViewController *viewController;

@end
-----------------------------------------------------------------------------------------------------------------------------------------

Now open AppDelegate.m file, we need to call one Helper class saveCurrentContext method to save the CoreData context when app is going to close by user.

1. So import CoreDataHelper class here

#import "CoreDataHelper.h"

2. update applicationWillTerminate method this way

- (void)applicationWillTerminate:(UIApplication *)application{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground    
    [[CoreDataHelper initCoreDataHelper] saveCurrentContext];
}


Finally our AppDelegate.m file look like 

-----------------------------------------------------------------------------------------------------------------------------------------
//
//  AppDelegate.m
//  CoreDataDemo
//
//  Created by RDC on 29/03/13.
//  Copyright (c) 2013 RDC World. All rights reserved.
//

#import "AppDelegate.h"
#import "ViewController.h"
#import "CoreDataHelper.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillTerminate:(UIApplication *)application{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground    
    [[CoreDataHelper initCoreDataHelper] saveCurrentContext];
}

//for now leave rest all empty methods..

@end
-----------------------------------------------------------------------------------------------------------------------------------------


Okay wrap it up this application. let's Run it.

Here is the output 



You can Find the ViewAll results in Console also.


Cheers!! we did it. 


You can find complete project source code zip file here : CoreDataDemo.zip (87.41 KB)


I Would love to here your thoughts !! 

9 comments:

  1. I like this summary. Very useful tutorial .
    You are right.Many mobile apps and web development companies are going for iphone envelopment.


    iphone apps development

    ReplyDelete
    Replies
    1. Hi.. Leeja,
      Nice to know that it was helpful for you :)

      Delete
  2. This comment has been removed by a blog administrator.

    ReplyDelete
    Replies
    1. Thank you!!
      I've some more articles to put here in upcoming days..
      BTW..I have sent you the response in mail.

      Delete
    2. Dear RDC! You are shown how to add, delete, search objects! tell pls how to update objects in the database

      Delete
  3. hi,
    thank you.....!! Very useful tutorial ........!!!

    ReplyDelete
  4. Very good tutorial and with sample script and it is amazing to develop and test.

    Thanks a lot.


    iPhone application development Service in India

    ReplyDelete
  5. Wow ...nice stepByStepInstructionsVeryUseful. ;-)

    ReplyDelete