iPhone Core Data Tutorial Part 1

Posted Oct 23, 2009 by eh9212 / comments 0 comments / Print / Font Size Decrease font size Increase font size

How to use core data on the iphone with one entity

If you need to insert data into your iPhone application, this tutorial will be for you. Before you start this tutorial, you need to have the latest version of Xcode.

To start, open up Xcode and press Shift - ⌘ - N. Under iPhone OS in the left pane, select Application, Navigation-based application. Check the Use Core Data for Storage option, click Choose..., and name the project CoreDataTutorial.

For better organization, highlight the CoreDataTutorialAppDelegate.m, press the action button - Add - New Group. Name it Data Model. Now double click your Data Model group and press ⌘ - N. Select Resource and double click on Data Model. Click next and name it recipes.xcdatamodel. Open up recipes.xcdatamodel and you will notice a new window with four different panes. The one on the left is for editing entities, the middle one is for editing attributes within those entities, the far-most one is for editing attribute or entity properties, and the one on the bottom is for entity mapping which will learn how to use later on.

In the left pane, click on the plus button at the bottom and name the entity Recipes. Make sure the Recipes entity is highlighted, click on the plus button in middle pane, and select add attribute. Name this attribute recipeName and add another attribute named cookingTime. In the middle pane under the tab Type or Destination, click on the up and down arrows and select String for both attributes. A type for an attribute means that what kind of data the attribute will hold. For example, if the attribute is a string, it will hold a phrase of text. If it is an Int 16, it will hold a number. Save recipes.xcdatamodel and close the window.

In the left pane of your project window, select recipes.xcdatamodel and press ⌘ - N. Select Coca Touch Class and you will notice that a new class has appeared named NSManagedObjectClass. This will create a .h and a .m file for our entity. Double click NSManagedObjectClass, click next, check the Recipes entity, and click Finish.

In case that the NSManagedObjectClass does not appear (I have had times when it doesn't) click cancel and make sure that the Recipes entity in your project's lower window pane is not highlighted. Then highlight the recipes.xcdatamodel file in the left window pane and press ⌘ - N. If the NSManagedObjectClass does not show up after trying this, highlight recipes.xcdatamodel and create a new NSObject class. Name it Recipes.h. Open up Recipes.h and type in the following code:

#import

 

 

@interface Recipes :  NSManagedObject

{

}

 

@property (nonatomic, retain) NSString * recipeName;

@property (nonatomic, retain) NSString * cookingTime;

 

@end

In the .m file, type in:

#import "Recipes.h"

 

 

@implementation Recipes

 

@dynamic recipeName;

@dynamic cookingTime;

 

@end

Now lets create some classes. Highlight the CoreDataTutorialAppDelegate.m and press ⌘ - N. Create a UIViewController named AddRecipeViewController and a UITableViewController named RecipeDetailViewController. Open up AddRecipeViewController.h and type in:

#import

@class Recipes;

 

@interface AddRecipeViewController : UIViewController {

Recipes *recipes;

UITextField *textFieldOne;

UITextField *textFieldTwo;

}

 

@property (nonatomic, retain) Recipes *recipes;

@property (nonatomic, retain) IBOutlet UITextField *textFieldOne;

@property (nonatomic, retain) IBOutlet UITextField *textFieldTwo;

 

@end

We need to import the Recipes class so we can editing the attributes that are in the Recipes entity. In the .m file, type in:

#import "AddRecipeViewController.h"

#import "Recipes.h"

 

@implementation AddRecipeViewController

 

@synthesize recipes, textFieldOne, textFieldTwo;

 

- (void)viewDidLoad {

[super viewDidLoad];

self.title = @"Add Recipe";

UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)];

self.navigationItem.leftBarButtonItem = cancelButton;

[cancelButton release];

 

UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithTitle:@"Save" style:UIBarButtonItemStyleDone target:self action:@selector(save)];

self.navigationItem.rightBarButtonItem = saveButton;

[saveButton release];

}

 

- (void)cancel {

[recipes.managedObjectContext deleteObject:recipes];

NSError *error = nil;

if (![recipes.managedObjectContext save:&error;]) {

// Handle error

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

exit(-1);  // Fail

}

[self dismissModalViewControllerAnimated:YES];

}

 

- (void)save {

recipes.recipeName = textFieldOne.text;

recipes.cookingTime = textFieldTwo.text;

NSError *error = nil;

if (![recipes.managedObjectContext save:&error;]) {

// Handle error

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

exit(-1);  // Fail

}

[self dismissModalViewControllerAnimated:YES];

}

Now you are probably wondering what this segment of code means:

NSError *error = nil;

if (![recipes.managedObjectContext save:&error;]) {

// Handle error

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

exit(-1);  // Fail

}

This is to save your work and insert it into your entity.   Open up AddRecipeViewController.xib and create a view with two UITextFields parallel to each other and UILabels left of the textFields. Next to the first UITextField, name the label Name: and next to the second UITextField, name the label Cooking Time:. Now connect the two UITextFields to the File's Owner. Make the first UITextField connected to textFieldOne and the second one textFieldTwo. Control click and drag from both of the UITextFields to the File's Owner and select Delegate. Before you save, make sure the File's Owners view is setting or else when you click on the add button in the RootViewController, your program will crash. Save it and quit out of Interface builder.

Double click on RecipeDetailViewController.h and enter this code:

#import

@class Recipes;

 

@interface RecipeDetailViewController : UITableViewController {

Recipes *recipes;

}

 

@property (nonatomic, retain) Recipes *recipes;

 

@end

In the .m file, enter:

#import "RecipeDetailViewController.h"

#import "Recipes.h"

 

@implementation RecipeDetailViewController

 

@synthesize recipes;

 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

return 1;

}

 

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

return 2;

}

 

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

 

static NSString *CellIdentifier = @"Cell";

 

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {

cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier] autorelease];

}

 

 

switch (indexPath.row) {

case 0:

cell.textLabel.text = @"Name";

cell.detailTextLabel.text = recipes.recipeName;

break;

case 1:

cell.textLabel.text = @"Cooking Time";

cell.detailTextLabel.text = recipes.cookingTime;

break;

default:

break;

}

return cell;

}

- (void)dealloc {Where it says

[recipes release];

[super dealloc];

}

 

@end

 

Save both files and open the RootViewController.m and type in the following code:

#import "RootViewController.h"

#import "AddRecipeViewController.h"

#import "Recipes.h"

#import "RecipeDetailViewController.h"

 

@implementation RootViewController

 

@synthesize fetchedResultsController, managedObjectContext;

 

 

#pragma mark -

#pragma mark View lifecycle

 

 

- (void)viewDidLoad {

[super viewDidLoad];

self.title = @"Recipes";

 

self.navigationItem.leftBarButtonItem = self.editButtonItem;

 

UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addRecipe)];

self.navigationItem.rightBarButtonItem = addButton;

[addButton release];

 

NSError *error = nil;

if (![[self fetchedResultsController] performFetch:&error;]) {

 

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

abort();

}

}

 

 

- (void)viewWillAppear:(BOOL)animated {

[super viewWillAppear:animated];

[self.tableView reloadData];

}

 

 

#pragma mark -

#pra[removed][removed]gma mark Add a new object

 

- (void)addRecipe {

AddRecipeViewController *addRecipeView = [[AddRecipeViewController alloc] initWithNibName:@"AddRecipeViewController" bundle:[NSBundle mainBundle]];

Recipes *recipes = (Recipes *)[NSEntityDescription insertNewObjectForEntityForName:@"Recipes" inManagedObjectContext:self.managedObjectContext];

addRecipeView.recipes = recipes;

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: addRecipeView];

[self.navigationController presentModalViewController:navController animated:YES];

[addRecipeView release];

}

 

 

#pragma mark -

#pragma mark Table view methods

 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

return [[fetchedResultsController sections] count];

}

 

 

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

id sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];

return [sectionInfo numberOfObjects];

}

 

 

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

 

static NSString *CellIdentifier = @"Cell";

 

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {

cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

}

 

NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];

cell.textLabel.text = [[managedObject valueForKey:@"recipeName"] description];

 

return cell;

}

 

 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

RecipeDetailViewController *recipeDetailView = [[RecipeDetailViewController alloc] initWithStyle:UITableViewStyleGrouped];

Recipes *recipes = (Recipes *)[fetchedResultsController objectAtIndexPath:indexPath];

recipeDetailView.recipes = recipes;

[self.navigationController pushViewController:recipeDetailView animated:YES];

}

 

 

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

 

if (editingStyle == UITableViewCellEditingStyleDelete) {

 

NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];

[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];

 

NSError *error = nil;

if (![context save:&error;]) {

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

abort();

}

}

}

 

 

#pragma mark -

#pragma mark Fetched results controller

 

- (NSFetchedResultsController *)fetchedResultsController {

 

if (fetchedResultsController != nil) {

return fetchedResultsController;

}

 

/*

Set up the fetched results controller.

*/

// Create the fetch request for the entity.

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

// Edit the entity name as appropriate.

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Recipes" inManagedObjectContext:managedObjectContext];

[fetchRequest setEntity:entity];

 

// Set the batch size to a suitable number.

[fetchRequest setFetchBatchSize:20];

 

// Edit the sort key as appropriate.

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"recipeName" ascending:NO];

NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

 

[fetchRequest setSortDescriptors:sortDescriptors];

 

// Edit the section name key path and cache name if appropriate.

// nil for section name key path means "no sections".

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];

aFetchedResultsController.delegate = self;

self.fetchedResultsController = aFetchedResultsController;

 

[aFetchedResultsController release];

[fetchRequest release];

[sortDescriptor release];

[sortDescriptors release];

 

return fetchedResultsController;

}

 

 

// NSFetchedResultsControllerDelegate method to notify the delegate that all section and object changes have been processed.

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {

// In the simplest, most efficient, case, reload the table view.

[self.tableView reloadData];

}

 

- (void)dealloc {

[fetchedResultsController release];

[managedObjectContext release];

[super dealloc];

}

 

 

@end

 

Where it says - (void)addRecipe, we are inserting a new entity into our database with this line of code:

Recipes *recipes = (Recipes *)[NSEntityDescription insertNewObjectForEntityForName:@"Recipes"inManagedObjectContext:self.managedObjectContext];

 

when we say addRecipeView.recipes = recipes; we are passing on the recipes entity to edit or view.

Now Click build and go and play around with it. Part 2 will be about how to use to entities and inset images into our database. The source code can be found here: http://sites.google.com/site/iprogramiphones/bukisatutorials/coredatatutorialpart1.

Check out Part 2: http://www.bukisa.com/articles/188059_iphone-core-data-tutorial-part-2.

Thanks for reading!

What kind of tutorial would you like next? Post your answer as a comment on this page.

 

Problems with coding? Email me @ edwardhinsa@gmail.com.

 

Have a dog and an iPod Touch and an iPhone? http://itunes.apple.com/WebObjects/MZStore.woa/wa/browserRedirect?url=itms://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=332655618&mt=8


Rate this Article:

Be the first to rate me.


* You must be logged in order to leave comments, please login or join us.

Comments

No comments yet.



Bookmark and Share
Sign up for our email newsletter
Name:
Email: