iOS:CoreData 一点通

去那里吧


iOS Core Data Tutorial With Example

In this tutorial ( iOS Core Data Tutorial ), we will learn how to save and fetch data in iPhone Apps and also manage relationships between them. Will will create a phone book core data project with complete source code provided in the end.

Final Project – iOS Core Data Tutorial

ios core data tutorial - Final Project

What is Core Data in iOS

Core Data is a powerful unified framework Provided by Apple for persisting data in the applications. It is cheap in terms of processes usage, and relationship between data can also be maintained easily.

Tutorial Overview

In this Tutorial , We will learn basic implementation of Core data

  • How to Add core data files to an existing Project.
  • Manage NSManageObject Classes.
  • Use Relationship among NSManageObjects.
  • Fetching data.
  • Showing Data to the user.

Initial Setup

This tutorial aims at core data implementation for beginners, so we have already set up the project with the views we needed and the controllers hierarchy.

For understanding the setup, you need to have basic knowledge of Table view controller and adding new project  (If you don’t know this , you can read our previous tutorials from here  )

Short note on already set up project (Project can be downloaded from link below )

Initial Project – download Link – iOS Core Data Tutorial

  • MainViewController – Initial View controller :  which contains a form to add new entry to your phone book and a button to show already added entry.
  • PhoneBookTableViewController : This will be used to show already added phone book entries.

You can download the initial project and run it and you will see the form to add entry and tapping show entry button will take you to table view controller (its empty as we have not added any data to it yet)

Now we will move on to adding core data functionality.

Add Missing Framework

  • Tap on project file , go to Targets.
  • Open the summary tab.
  • Click on ‘+’ inside Linked Frameworks and Libraries (shown as 1 in the screen).
  • Add CoreData.Framework.
  • Move this framework under Framework folder inside project Navigator Tab.

ios core data tutorial - adding framework

Adding Missing Files

  • From Xcode,click on the File Tab and go to new file (or click Cmd + N).
  • Select Core data from the iPhone OS group.
  • Select Data Model and click Next.
  • Give the file a name (the project name is a good choice) and click Create.

ios Core Data Tutorial adding Model File

Now we have an Empty file with name “PhoneBook.xcdatamodeld”

Adding Missing Objects

1.  Open PhoneBook-Prefix.pch (Your project pch file ) and add following code to it

1
#import <CoreData/CoreData.h>

This is added to make project compile core data  framework and make it available for all files in the project as it is being added to .pch file (pre-compiled header)

2. Open AppDelegate.h and add following code (objects)

1
2
3
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator ;

As you can see, We have created instance of  NSManagedObjectModel , NSManagedObjectContext , NSPersistentStoreCoordinator respectively , that will be used to deal with data base .

3. Now Open AppDelegate.m and add following code

1
2
3
4
5
6
@implementation ApDelegate
 
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
 
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

4. To the same file (AppDelegate.m) , add Following Methods also :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 1
- (NSManagedObjectContext *) managedObjectContext {
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator: coordinator];
}
 
return _managedObjectContext;
}
 
//2
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
 
return _managedObjectModel;
}
 
//3
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: @"PhoneBook.sqlite"]];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
if(![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeUrl options:nil error:&error]) {
/*Error for store creation should be handled in here*/
}
 
return _persistentStoreCoordinator;
}
 
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}

1) Method will be returning “managedObjectContext” object associated with out data base file (Sqlite ).

2) Method will be returning “managedObjectModel” object associated with out data base file (Sqlite ).

3) Method will be returning “persistentStoreCoordinator” object associated with out data base file (Sqlite ).

Some useful Definitions

Persistent Store Coordinator:

As the name suggest it is a coordinator , that coordinates between manage object context and low level file saved in our data base (Sqlite file) , you do not have to think much about it as this stage. We are not gonna use it directly, it will only be used while setting NSManageObjectContext . Linking it to our Persistent store coordinator which in turn will be linked with our Sqlite file (PhoneBook.sqlite for our case) .

Managed object context

You can think of a managed object context as an intelligent scratch pad. When you fetch objects from a persistent store, you bring temporary copies onto the scratch pad . You can then modify those objects however you like. Unless you actually save those changes, however, the persistent store remains unaltered.

This will be most important as we will be using it to make queries on our data (fetching , updating , deleting and adding data).

NSManageObject Model 

A managed object model is an instance of the NSManagedObjectModel class. It describes a schema (contains definitions) for objects (also called entities )—that you use in your application.

Properties (Attributes of entity )

An entity’s properties are its attributes and relationships. Amongst other features, each property has a name and a type. A property name cannot be the same as any no-parameter method name of NSObject or NSManagedObject—for example, you cannot give a property the name “description” (see NSPropertyDescription).

Generating Our Model

  1. Tap on “PhoneBook.xcdatamodeld”
  2. You will see a screen like this

ios Core Data Tutorial Generate Model

1) Tap this Button to add New Entity

2) Tap this to Add new Property (Attribute) to selected Entity.

3) Tap this to Add new Relationship to selected Entity.

4) This Column will tell you the Attribute name.

5) This Column will tell you the Attribute Type.

Using Above info , we have created our Entity named “Record” with 3 Attributes as shown in screen :

ios core data tutorial - model Created

1) This Text  (Record) will be used as class name when you use auto generate. (just remember it for now, Auto generate process will be explained below).

Auto Generating NSManageObject class

Go to File tab and tap on new file ( or Cmd + N) when the ”PhoneBook.xcdatamodeld” is still open

  • Select Core data from the iPhone OS group.
  • Select NSManageObjectSubclass and click Next
  • Record.h and Record.m will be created automatically with all the properties defined.

Now run the project , it will run as before. If there is any warning or error. 

You may have missed any step check all the steps again. But still there is no data as we have not yet saved any  Records to our Data base.

Saving Records to Database

So far , we have added core data files , framework and generating our model file .

Now, We are going to the most important and useful part of the tutorial,

We are going to add Our data to Data base.

 Open MainViewController.m

Add following property   (write below code above method definitions)

1
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

Import Required header Files

1
2
#import "Record.h"
#import "AppDelegate.h"

Add following code to viewDidLoad Method

1
2
3
4
//1
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
//2
self.managedObjectContext = appDelegate.managedObjectContext;

1)  Make an instance of AppDelegate .

2)  Referencing manageObjectContext : manageObjectContext of the Controller points to AppDelegate’s manageObjectContext object.

Change addPhoneBookEntry method to following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- (IBAction)addPhoneBookEntry:(id)sender
{
   // Add Entry to PhoneBook Data base and reset all fields
 
//  1
   Record * newEntry = [NSEntityDescription insertNewObjectForEntityForName:@"Record"
                                                     inManagedObjectContext:self.managedObjectContext];
//  2
   newEntry.firstName = self.firstNameTextfield.text;
   newEntry.lastName = self.lastNameTextfield.text;
   newEntry.city = self.cityTextfield.text;
//  3
   NSError *error;
   if (![self.managedObjectContext save:&error]) {
     NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
   }
//  4
   self.firstNameTextfield.text = @"";
   self.lastNameTextfield.text = @"";
   self.cityTextfield.text = @"";
   self.phoneNumber1.text = @"";
   self.phoneNumber2.text = @"";
//  5
   [self.view endEditing:YES];
}

1) Creates, configures, and returns an instance of the Record class .

2) We add Values to different Attributes of Record class object.

3) Entity value is saved to data base (Without this our data won’t persist in the memory ). As i already told you its like scratch pad unless you save the work. it will be lost when scratch pad is erased.

4) Removing All Text field in Texfields.

5) Dismissing Keyboard.

ios core data tutorial - AddingData

Screen showing an Example Record

Show Records In TableView

1. Open AppDelegate.h and add Following Methods

1
-(NSArray*)getAllPhoneBookRecords;

2 . Now Open  AppDelegate.m and add implementation of the Method added.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-(NSArray*)getAllPhoneBookRecords
{
   // initializing NSFetchRequest
   NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
 
   //Setting Entity to be Queried
   NSEntityDescription *entity = [NSEntityDescription entityForName:@"Record"
                                             inManagedObjectContext:self.managedObjectContext];
   [fetchRequest setEntity:entity];
   NSError* error;
 
   // Query on managedObjectContext With Generated fetchRequest
   NSArray *fetchedRecords = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
 
   // Returning Fetched Records
   return fetchedRecords;
}

3.  Now Open PhoneBookTableViewController.m

Firstly Import some header Files

1
2
#import "AppDelegate.h"
#import "Record.h"

Add a Property of type NSArray to save fetched Objects (Records)

1
@property (nonatomic,strong)NSArray* fetchedRecordsArray;

Modify viewDidLoad Method to look like following

1
2
3
4
5
6
7
8
9
- (void)viewDidLoad
{
   [super viewDidLoad];
   AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
 
   // Fetching Records and saving it in "fetchedRecordsArray" object
   self.fetchedRecordsArray = [appDelegate getAllPhoneBookRecords];
   [self.tableView reloadData];
}

Now , we will use this array as a data source to update our table view

Modify UITableViewData source method to incorporate our fetchedRecordsArray to populate the table cells

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
     // Return the number of sections.
     return1;
}
 
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
     // Return the number of rows in the section.
   return [self.fetchedRecordsArray count];
}
 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   staticNSString *CellIdentifier = @"PhoneBookCellIdentifier";
   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
   Record * record = [self.fetchedRecordsArray objectAtIndex:indexPath.row];
   cell.textLabel.text = [NSString stringWithFormat:@"%@ %@, %@ ",record.firstName,record.lastName,record.city];
   return cell;
}

Now Run the program again, and tap on show PhoneBook. You will see Records like this

ios core data tutorial - Records Shown

But wait a minute, what about the phone numbers ? thinking-face

Oh Ya! We have not added relationships to show Phone Numbers Yet.

Adding Relationships

Relationship helps to maintain Records in neat and clean way .

Creating a relationship in a managed object model is straightforward, but there are a number of aspects of a relationship that you need to specify properly. The most immediately obvious features are the relationship’s name, the destination entity, and the cardinality (is it a to-one relationship, or a to-many relationship).

Updating Model Files

1. Add Entity to save phone number :

Add New Entity named as “PhoneNumber”  with one Attribute named “number” of type String.

2. Deciding Type of Relationship: 

Now we have to make a relationship between Record and Phone Number . Which type of relationship to be used will be decided by the data.

We have two phone number for every record  so lets use one to many relationship.

3. Making Relationship

Go to Record and tap on plus to add relationship with name “phoneNumbers” , add PhoneNumber Entity as Destination

Similarly go to PhoneNumber , make a relationship which is to be used as inverse relationship.

Name this Relation as record with Record as its destination.

Following Screen Explains you Various things You need to understand :

ios core data tutorial - Relationships

1) This Column shows the various Relationships name.

Come back to Record Entity , tap on relation .

“M” Shown before name of relationship means it is a one to many relationship

“O” means it is one to one relationship (we don’t have it here)

2) This Column shows the Destination class for that Relation.

3) This Column shows the Inverse Relationship name.

4) This Shows the Checkbox which is to be checked to make relationships one to many .

5) Show Various Entities in the Model with the open one is shown as Highlighted.

Why to add Inverse Relationships :

Here are the Lines from Apple Documentation ..

You should typically model relationships in both directions, and specify the inverse relationships appropriately. Core Data uses this information to ensure the consistency of the object graph if a change is made. (For Example if a  object is deleted)

Now we have added the Relationship By its time to change it to one to many :

Come back to Record Entity , tap on relation .

From the right menu , tap on Data Model inspector and define relationship as one to many as shown in above screen :

After Completing this task PhoneNumber Entity will look like this

ios core data tutorial - Entity

Now Run the project and Try to add Record with Phone Numbers ?

Project Crashes!!   

What went wrong !

Important Note :

If you make any changes in core data model , you need to delete app from simulator (or device) and run the app again. However there is a technique for core data migration but that would be covered in advanced tutorial. For now , you need not to worry about it. You also have to generate the NSManageObject Class again so that the changes will be reflected in the corresponding class

AutoGenerating Classes Again

Delete already generating Record.h and Record.m files.

Open ”PhoneBook.xcdatamodeld” and select both Entities .

Go to File tab and tap on new file ( or Cmd + N) when the ”PhoneBook.xcdatamodeld” is still open

  • Select Core data from the iPhone OS group
  • Select NSManageObjectSubclass and click Next
  • Both Classes will be created with all the attributes and relationship as defined.

So , We delete the app from simulator ,clean the project and build it again.

And Hurray ! That works

But still no Phone number info. Because we have created the relationship but has not used it to save our data.

Saving Data Using Relationships

1 . Open MainViewController.m

Firstly Import Header Files

1
#import "PhoneNumber.h"

Modify addPhoneBookEntry Method to look like Following

points 6,7,8 has been added to save data in relationship .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
- (IBAction)addPhoneBookEntry:(id)sender
{
   // Add Entry to PhoneBook Data base and reset all fields
 
//  1
   Record * newEntry = [NSEntityDescription insertNewObjectForEntityForName:@"Record"
                                                     inManagedObjectContext:self.managedObjectContext];
//  2
   newEntry.firstName = self.firstNameTextfield.text;
   newEntry.lastName = self.lastNameTextfield.text;
   newEntry.city = self.cityTextfield.text;
 
//  6
   PhoneNumber * phoneNumber1 = [NSEntityDescription insertNewObjectForEntityForName:@"PhoneNumber"
                                                              inManagedObjectContext:self.managedObjectContext];
   phoneNumber1.number = self.phoneNumber1.text;
 
//  7
   PhoneNumber * phoneNumber2 = [NSEntityDescription insertNewObjectForEntityForName:@"PhoneNumber"
                                                              inManagedObjectContext:self.managedObjectContext];
   phoneNumber2.number = self.phoneNumber2.text;
//  8
   newEntry.phoneNumbers = [NSSet setWithObjects:phoneNumber1 ,phoneNumber2, nil];
 
//  3
   NSError *error;
   if (![self.managedObjectContext save:&error]) {
     NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
   }
//  4
   self.firstNameTextfield.text = @"";
   self.lastNameTextfield.text = @"";
   self.cityTextfield.text = @"";
   self.phoneNumber1.text = @"";
   self.phoneNumber2.text = @"";
//  5
   [self.view endEditing:YES];
}

6)   Making an Entity Object For PhoneNumber Class and saving phoneNumber1 in it.

7) Similarly making one more object to save PhoneNumber2.

8) Adding these Objects as relationships to Record object. (There are no Array in Data base, only NSSet).

Now , Run the project and add more objects. See this Object In table view.

Still we don’t see Any Phone Number , We need to change Cell Data to show both phone numbers.

2. open PhoneBookTableViewController.m

Firstly Import Header Files

1
#import "PhoneNumber.h"

Modify cellForRowAtIndexPath Data Source Method to look like following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   static NSString *CellIdentifier = @"PhoneBookCellIdentifier";
   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
   Record * record = [self.fetchedRecordsArray objectAtIndex:indexPath.row];
   cell.textLabel.text = [NSString stringWithFormat:@"%@ %@, %@ ",record.firstName,record.lastName,record.city];
 
   //1
   PhoneNumber* phoneNumber1 = (PhoneNumber*)[[record.phoneNumbers allObjects] objectAtIndex:0];
   PhoneNumber* phoneNumber2 = (PhoneNumber*)[[record.phoneNumbers allObjects] objectAtIndex:1];
   //2
   cell.detailTextLabel.text = [NSString stringWithFormat:@"Phone Numbers- %@,%@ ",phoneNumber1.number ,phoneNumber2.number];
 
   return cell;
}

1) PhoneNumber object extracted from FetchedObjectsArray Records.

2) “number” Extracted from PhoneNumber Objects and shown in Cell.

Add Some More Entries with all the fields inserted and see that in PhoneBookTableViewController

BinGo !

We have Our Data in here!

ios core data tutorial - Relationships Records Shown

We are done here with the first part of this Tutorials , In this Tutorial we have learnt how to Add Core Data in Existing Projects :

  • How to add core data files.
  • Making Model Entities with no Relationships.
  • How to add Relationships
  • How to fetchData and show them in TableView

Source Code – iOS Core Data

Download the complete source code here and if you have any questions or feedback, leave me a comment.

What Next

In the Next Part of this Tutorial, we will deal with updating (or deleting ) already existing records in our core data.

iOS Core Data Tutorial With Example (Part -2 )


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小涵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值