articles

Home / DeveloperSection / Articles / iOS : Creating Sample on Core Data

iOS : Creating Sample on Core Data

Tarun Kumar2965 29-Jul-2015

Here we are going to create a sample using Core Data and our objective is to allow the user to enter name, address and phone number information into a database and then search for specific contacts based on the contact’s name.


To create the sample application project follow the steps:


1.    Launch Xcode and select the option to create a new project.

2.       In the new project window, select the Empty Application option.

3.       Next screen make sure that the Device Family menu is set to iPhone and that the check box next to Use Core Data is selected. In the Product Name and Class Prefix fields enter coreData.

4.       Next to select a location to store the project files. Xcode will create the new project and display the main project window. In addition to the usual files that are present when creating a new project, this time an additional file named coreData.xcdatamodeld is also created. This is the file where the entity descriptions for our data model are going to be stored.

5.       Entity description defines the model for our data, to create the entity for the Core Data application, select the coreData.xcdatamodeld file to load the entity editor: To create a new entity, click on the Add Entity button located in the bottom panel. In the text field that appears beneath the Entities heading name the entity Contacts. With the entity created.

6.   Next step is to add some attributes that represent the data that is to be stored. So, click on the Add Attribute button and name the attribute name and set the Type to String. Repeat these steps to add two other String attributes named address and phone respectively, now entity has defined. 

The view controller class to the application we need to modify our app delegate to make this the root view controller. In project navigator, select the AppDelegate.h file and modify it to add a reference to our new view controller.

Instance of the view controller declared in the interface file we now need to modify the applicationDidFinishLaunchingWithOptions method located in the AppDelegate.m implementation file to initialize and allocate the ViewController instance and assign it as the window view so that it is visible to the user. Now we have to import ViewController.h into this file and synthesize accessors for the viewController object.

Adding Actions and Outlets to the View Controller : Instances of our Contacts application, our Core Data example will include a user interface that needs to accept and display name, address and phone information and to react to the selection of the save and find buttons, a status label will be used to provide the user with feedback. To declare the outlets and actions associated with these user interface components, select the ViewController.h file and modify the class declaration.

Next, select the ViewController.m implementation file, add an @synthesize directive for the outlets, import the AppDelegate.h file and add template methods for the two declared actions:

 

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 may 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

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.


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. 

 

Designing the User Interface

With the actions and outlets defined, now is a good time to design the user interface and establish the connections so select the ViewController.xib file to begin the design work. The user interface and corresponding connections used in this tutorial are the same as those in previous data persistence chapters.

Before proceeding, stretch the status label so that it covers most of the width of the view. Finally, edit the label and remove the word “Label” so that it is blank.

Next, connect the three text fields and status label to the name, address, phone and status outlets respectively by holding down the Ctrl key and clicking and dragging from File’s Owner icon to the corresponding component. From the resulting menu select the outlet corresponding to the selected view object.

The last step involves connecting the two buttons to the corresponding actions. First, display the Connections Inspector (View -> Utilities -> Show Connections Inspector) then select the Save button. Click inside the small circle next to the Touch Up Inside event in the Connections Inspector panel and drag the blue line to the File’s Owner object. To establish the connection, select saveData from the resulting menu. Repeat these steps to connect the Find button to the findContact action.

After doing all those things storyboard will look like this:

iOS : Creating Sample on Core Data

 

Source Code of Our Program is Here:

AppDelegate.h

#import <UIKit/UIKit.h>

#import <CoreData/CoreData.h>

 

@class CoreDataViewController;

 

@interface AppDelegate : UIResponder <UIApplicationDelegate> {

    CoreDataViewController *viewController;

}

@property (strong, nonatomic) IBOutlet CoreDataViewController *viewController;

@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

 

ViewController.h


#import <UIKit/UIKit.h>

#import <CoreData/CoreData.h>

 

@interface ViewController : UIViewController<NSFetchedResultsControllerDelegate,UITableViewDelegate,UITextFieldDelegate,UITableViewDataSource> {

    UITextField *name;

    UITextField *address;

    UITextField *phone;

    UILabel     *status;

    IBOutlet UITableView *MyTableView;

}

@property (strong, nonatomic) IBOutlet UITextField *name;

@property (strong, nonatomic) IBOutlet UITextField *address;

@property (strong, nonatomic) IBOutlet UITextField *phone;

@property (strong, nonatomic) IBOutlet UILabel *status;

@property NSFetchedResultsController *fetchResultController;

@property(nonatomic, retain) IBOutlet UITableView *MyTableView;

 

- (IBAction)saveData:(id)sender;

- (IBAction)findContact:(id)sender;

 

@end

 

AppDelegate.m


#import "AppDelegate.h"

#import "ViewController.h"

 

@implementation AppDelegate

 

@synthesize window = _window;

@synthesize managedObjectContext = __managedObjectContext;

@synthesize managedObjectModel = __managedObjectModel;

@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;

@synthesize viewController;

.

.

@end

 

GlobalClass.h


#import <Foundation/Foundation.h>

@interface GlobalClass : NSObject <UIApplicationDelegate>

 

+ (NSManagedObjectContext *)managedObjectContext;

+ (NSPersistentStoreCoordinator *)persistentStoreCoordinator;

+ (NSManagedObjectModel *)managedObjectModel;

+(NSFetchedResultsController*)GetFetchResultControllerWithModelName:

(NSString*)Model SortingKey:(NSString*)Key;

 

@end

 

GlobalClass.m


#include <CoreData/CoreData.h>

#import "GlobalClass.h"

 

@implementation GlobalClass

static NSManagedObjectContext *managedObjectContext;

static NSManagedObjectModel *managedObjectModel;

static NSPersistentStoreCoordinator *persistentStoreCoordinator;

 

+ (NSManagedObjectContext *)managedObjectContext

{

    if (managedObjectContext != nil) {

        return managedObjectContext;

    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

    if (coordinator != nil) {

        managedObjectContext = [[NSManagedObjectContext alloc] init];

        [managedObjectContext setPersistentStoreCoordinator:coordinator];

    }

    return managedObjectContext;

}

 

+ (NSPersistentStoreCoordinator *)persistentStoreCoordinator

{

    if (persistentStoreCoordinator != nil) {

        return persistentStoreCoordinator;

    }

    NSURL *documentroot=[[[NSFileManager defaultManager] URLsForDirectory:

NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];

    NSURL *storeURL = [documentroot URLByAppendingPathComponent:@"CoreDataModel.sqlite"];

    NSError *error = nil;

    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:

[self managedObjectModel]];

    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:

nil URL:storeURL options:nil error:&error]) {

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

        abort();

    }    

    return persistentStoreCoordinator;

}

+ (NSManagedObjectModel *)managedObjectModel

{

    if (managedObjectModel != nil) {

        return managedObjectModel;

    }

    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreDataModel" withExtension:

@"momd"];

    managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

    return managedObjectModel;

}

 

+(NSFetchedResultsController*)GetFetchResultControllerWithModelName:(NSString*)Model

SortingKey:(NSString*)Key{

    NSFetchRequest *fetchrequest=[[NSFetchRequest alloc] initWithEntityName:Model];

    [fetchrequest setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor

sortDescriptorWithKey:Key ascending:YES]]];

    return [[NSFetchedResultsController alloc]initWithFetchRequest:fetchrequest

managedObjectContext:managedObjectContext

sectionNameKeyPath:nil cacheName:nil];

}

 

@end

 

ViewController.m


#import "ViewController.h"

#import "AppDelegate.h"

#include "GlobalClass.h"

#define NAME_LENGTH 15

#define ADDRESS_LENGTH 20

#define PHONE_LENGTH 10

 

@interface ViewController (){

}

@end

 

@implementation ViewController

@synthesize name;

@synthesize address;

@synthesize phone;

@synthesize status;

@synthesize fetchResultController;

@synthesize MyTableView;

 

- (void)viewDidLoad

{

    [super viewDidLoad];

    [GlobalClass managedObjectContext];

// Do any additional setup after loading the view, typically from a nib.

    self.name.delegate=self;

    self.address.delegate=self;

    self.phone.delegate=self;

    

    self.fetchResultController=[GlobalClass GetFetchResultControllerWithModelName:@"Contacts"

SortingKey:@"name"];

    self.fetchResultController.delegate=self;

    NSError *error;

    [self.fetchResultController performFetch:&error];

    if(error){

        NSLog(@"%@",error);

    }

}

 

- (void)viewDidUnload

{

    // Release any retained subviews of the main view.

    // e.g. self.myOutlet = nil;

    self.name = nil;

    self.address = nil;

    self.phone = nil;

    self.status = nil;

}

 

// delegate method of table

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

  NSLog(@"NoOfRows: %ld",(long)[self.fetchResultController fetchedObjects].count);

    return (int)[self.fetchResultController fetchedObjects].count;

}

 

// delegate method of table

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)

indexPath{

    static NSString *simpleTableIdentifier = @"Contact";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];

    if (cell == nil) {

        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:

simpleTableIdentifier];

    }

    NSArray *arr = [fetchResultController fetchedObjects];

    NSDictionary *firstObject = [arr objectAtIndex:indexPath.row];

    

    cell.textLabel.text = [firstObject valueForKey:@"name"];

    [[cell detailTextLabel] setLineBreakMode:UILineBreakModeCharacterWrap];

   

    cell.detailTextLabel.text = [NSString stringWithFormat:@"%@  %@",[firstObject valueForKey:

@"address"],[firstObject valueForKey:@"phone"]];

    return cell;

}

 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);

}

 

// save Button clicked action

- (IBAction)saveData:(id)sender {

    if(name.text.length == 0 || address.text.length == 0 || phone.text.length == 0){

        NSString *tName;

        if(name.text.length == 0){

             tName = @"Name";

        }else if(address.text.length==0) {

            tName = @"Address";

        }else if(phone.text.length==0) {

            tName = @"Phone";

        }

            

        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Alert" message:

[NSString stringWithFormat:@"%@ will not be Blank.",tName]

delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];        

        [alertView show];

    }else {    

    

        NSManagedObject *newContact;

        newContact = [NSEntityDescription

                      insertNewObjectForEntityForName:@"Contacts"

                      inManagedObjectContext:[GlobalClass managedObjectContext]];

        [newContact setValue:name.text forKey:@"name"];

        [newContact setValue:address.text forKey:@"address"];

        [newContact setValue:phone.text forKey:@"phone"];

   

        NSError *error;

        [[GlobalClass managedObjectContext] save:&error];

        name.text = @"";

        address.text = @"";

        phone.text = @"";

        if(!error)

        {

            status.text = [[NSString alloc]initWithFormat:@"Contact Saved"];        

        }

        else {

            status.text = [[NSString alloc]initWithFormat:@"Somethig Wrong"];

        }

        

        [self.view endEditing:YES]; //disabling keyboard

    }

}

 

// find Contact clicked action

- (IBAction)findContact:(id)sender {

    NSEntityDescription *entityDesc = [NSEntityDescription entityForName:@"Contacts"

inManagedObjectContext:[GlobalClass managedObjectContext]];

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

    [request setEntity:entityDesc];

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"(name = %@)", name.text];

    [request setPredicate:pred];

    NSManagedObject *matches = nil;

    NSError *error;

    NSArray *objects = [[GlobalClass managedObjectContext] executeFetchRequest:request

error:&error];

    if ([objects count] == 0) {

        status.text = @"No matches";

    } else {

        matches = [objects objectAtIndex:0];

        //address.text = [matches valueForKey:@"address"];

        //phone.text = [matches valueForKey:@"phone"];

        status.text = [NSString stringWithFormat: @"%d matches found", [objects count]];

    }

}

 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

//    [self.name resignFirstResponder];

//    [self.address resignFirstResponder];

//    [self.phone resignFirstResponder];

    [self.view endEditing:YES];

}

 

// called to reset the table view when a new data will be inserted

-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath{

    //NSLog(@"%@",anObject);

    //NSLog(@"%@",[[self.fetchResultController fetchedObjects] objectAtIndex:10]);

    //NSLog(@"%ld",(long)[self.fetchResultController fetchedObjects].count);

    [MyTableView reloadData];

}

 

// called when textField editing will be done

- (void)textFieldDidEndEditing:(UITextField *)textField{

    [textField setBackgroundColor:[UIColor clearColor]];

}

 

// called when textField editing will be started

- (void)textFieldDidBeginEditing:(UITextField *)textField{

    [textField setBackgroundColor:[UIColor yellowColor]];

}

 

// called when ever a key is pressed to insert the value into textField

// it is used to setting validation on textFields

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range

replacementString:(NSString *)string {

if (string.length==0) {

      returnYES;

  }

    switch (textField.tag) {

        case 1:

            if(name.text.length < NAME_LENGTH) {

                return YES;

            }

            break;

        case 2:

            if(address.text.length < ADDRESS_LENGTH) {

                return YES;

            }

            break;

        case 3:

            if(phone.text.length < PHONE_LENGTH) {

                return YES;

            }

            break;

        default:

            break;

    }

    return NO;

}

 

@end

 

Running the sample of our Application

Click on the Run button located in the toolbar of the main Xcode project window. If errors are reported check the syntax of the code you have written, using the error message provided by Xcode as guidance. Once the application compiles it will launch and load into the iOS Simulator.

Enter contact information to add the contact in the contact list and you can also find the contacts, provide the name and click the Find button if any record is exist then message will be display like “3 matches found” if having 2 contacts with the same name. see the example below:

iOS : Creating Sample on Core Data

and after when you will find any contact from the contacts, if have same names then it will display like this:

iOS : Creating Sample on Core Data


Updated 07-Sep-2019

Leave Comment

Comments

Liked By