1.Core Data 是数据持久化存储的最佳方式

2.数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型

在Mac OS X 10.5Leopard及以后的版本中,开发者也可以通过继承NSPersistentStore类以创建自定义的存储格式

3.好处:能够合理管理内存,避免使用sql的麻烦,高效

4.构成:

(1)NSManagedObjectContext(被管理的数据上下文)

操作实际内容(操作持久层)

作用:插入数据,查询数据,删除数据

(2)NSManagedObjectModel(被管理的数据模型)

数据库所有表格或数据结构,包含各实体的定义信息

作用:添加实体的属性,建立属性之间的关系

操作方法:视图编辑器,或代码

(3)NSPersistentStoreCoordinator(持久化存储助理)

相当于数据库的连接器

作用:设置数据存储的名字,位置,存储方式,和存储时机

(4)NSManagedObject(被管理的数据记录)

相当于数据库中的表格记录

(5)NSFetchRequest(获取数据的请求)

相当于查询语句

(6)NSEntityDescription(实体结构)

相当于表格结构

(7)后缀为.xcdatamodeld的包

里面是.xcdatamodel文件,用数据模型编辑器编辑

编译后为.momd或.mom文件

5.依赖关系

Core Data (2)-备用_数据库

二、基于SQLite数据库时,Core Data的简单使用

和SQLite的区别:只能取出整个实体记录,然后分解,之后才能得到实体的某个属性

1.构建流程

包括:创建数据上下文,创建数据模型,创建数据持久化存储助理

(1)若是新建的工程,选择空白应用程序,next

Core Data (2)-备用_#import_02

勾选Use Core Data选项

Core Data (2)-备用_iOS 本地存储_03

此时生成的工程文件AppDelegate中,会自动生成被管理的数据上下文等相关代码

(2)比如AppDelegate.h文件中,自动生成




1


2


3


4


5


6




​@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;​


​@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;​


​@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;​


 


​- (​​​​void​​​​)saveContext;​


​- (NSURL *)applicationDocumentsDirectory;​



方法saveContext表示:保存数据到持久层(数据库)

方法applicationDocumentsDirectory表示:应用程序沙箱下的Documents目录路径

(例如/var/mobile/Applications/5FG80A45-DFB5-4087-A1B1-41342A977E21/Documents/)

(3)比如AppDelegate.h文件中,自动生成



1


2


3




​@synthesize managedObjectContext = __managedObjectContext;​


​@synthesize managedObjectModel = __managedObjectModel;​


​@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;​



保存数据到持久层




1


2


3


4




​- (​​​​void​​​​)applicationWillTerminate:(UIApplication *)application​


​{​


​[self saveContext];​


​}​




1


2


3


4


5


6


7


8


9


10


11




​- (​​​​void​​​​)saveContext​


​{​


​NSError *error = nil;​


​NSManagedObjectContext *managedObjectContext = self.managedObjectContext;​


​if​​ ​​(managedObjectContext != nil) {​


​if​​ ​​([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {​


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


​abort​​​​();​


​} ​


​}​


​}​



Documents目录路径



1


2


3


4




​- (NSURL *)applicationDocumentsDirectory​


​{​


​return​​ ​​[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];​


​}​



被管理的数据上下文

初始化的后,必须设置持久化存储助理




1


2


3


4


5


6


7


8


9


10


11


12




​- (NSManagedObjectContext *)managedObjectContext​


​{​


​if​​ ​​(__managedObjectContext != nil) {​


​return​​ ​​__managedObjectContext;​


​}​


​NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];​


​if​​ ​​(coordinator != nil) {​


​__managedObjectContext = [[NSManagedObjectContext alloc] init];​


​[__managedObjectContext setPersistentStoreCoordinator:coordinator];​


​}​


​return​​ ​​__managedObjectContext;​


​}​



被管理的数据模型

初始化必须依赖.momd文件路径,而.momd文件由.xcdatamodeld文件编译而来




1


2


3


4


5


6


7


8


9




​- (NSManagedObjectModel *)managedObjectModel​


​{​


​if​​ ​​(__managedObjectModel != nil) {​


​return​​ ​​__managedObjectModel;​


​}​


​NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@​​​​"TestApp"​​ ​​withExtension:@​​​​"momd"​​​​];​


​__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];​


​return​​ ​​__managedObjectModel;​


​}​



持久化存储助理

初始化必须依赖NSManagedObjectModel,之后要指定持久化存储的数据类型,默认的是NSSQLiteStoreType,即SQLite数据库;并指定存储路径为Documents目录下,以及数据库名称



​​



1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16




​- (NSPersistentStoreCoordinator *)persistentStoreCoordinator​


​{​


​if​​ ​​(__persistentStoreCoordinator != nil) {​


​return​​ ​​__persistentStoreCoordinator;​


​}​


​NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@​​​​"TestApp.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;​


​}​



如果不是新工程,也可以自己写入相关代码

(4)此外还生成了TestApp.xcdatamodeld文件

(5)还自动链接了CoreData.framework

(6)在预编译头.pch文件中,加入导入了CoreData.h头文件






1




​#import <CoreData/CoreData.h>​



2.创建数据模型(数据模型编辑器操作)

(1)创建实体

选中.xcodedatamodel对象

Core Data (2)-备用_iOS 本地存储_04

在右边的数据模型编辑器的底部工具栏点击Add Entity添加实体

Core Data (2)-备用_iOS 本地存储_05

在最右侧栏对实体命名

Core Data (2)-备用_#import_06

(2)创建实体属性

选中实体,点击底部工具栏的Add Attribute添加属性

Core Data (2)-备用_数据_07

选中新添加的属性,对属性进行命名,并设置属性的数据类型Attribute Type

Core Data (2)-备用_iOS 本地存储_08

(3)为两个实体建立关系

选中一个实体,在底部工具栏点击Add Relationship添加关系

Core Data (2)-备用_数据模型_09

选中新关系,对关系添加名称,目标destination设置为另个实体

Core Data (2)-备用_数据_10

(4)建立返回关系

(当你建立一个目标关系,最好建立一个返回关系)

在另一个实体中建立一个关系并命名,设置目标对象为这之前的实体

并在Inverse属性选这之前的关系名称

Core Data (2)-备用_数据模型_11

(5)设置两个关系的删除规则Delete Rule,都为关联模式

关联模式cascade:其中一个数据被删除,另一个实体中的数据也会跟着删除

Core Data (2)-备用_iOS 本地存储_12

(6)最终两个对象的关系图为

Core Data (2)-备用_数据模型_13

切换Editor Stype按钮

Core Data (2)-备用_数据库_14

会看到另一种编辑方式:

Core Data (2)-备用_数据库_15

Core Data (2)-备用_数据_16

 3.插入数据

在AppDelegate.m的application:didFinishLaunchingWithOptions:方法里,调用自定义方法

insertCoreData插入数据,代码如下:





1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19


20


21


22


23




​- (​​​​void​​​​)insertCoreData​


​{​


​NSManagedObjectContext *context = [self managedObjectContext];​


 


​NSManagedObject *contactInfo = [NSEntityDescription insertNewObjectForEntityForName:@​​​​"ContactInfo"​​ ​​inManagedObjectContext:context];​


​[contactInfo setValue:@​​​​"name B"​​ ​​forKey:@​​​​"name"​​​​];​


​[contactInfo setValue:@​​​​"birthday B"​​ ​​forKey:@​​​​"birthday"​​​​];​


​[contactInfo setValue:@​​​​"age B"​​ ​​forKey:@​​​​"age"​​​​];​


 


​NSManagedObject *contactDetailInfo = [NSEntityDescription insertNewObjectForEntityForName:@​​​​"ContactDetailInfo"​​ ​​inManagedObjectContext:context];​


​[contactDetailInfo setValue:@​​​​"address B"​​ ​​forKey:@​​​​"address"​​​​];​


​[contactDetailInfo setValue:@​​​​"name B"​​ ​​forKey:@​​​​"name"​​​​];​


​[contactDetailInfo setValue:@​​​​"telephone B"​​ ​​forKey:@​​​​"telephone"​​​​];​


 


​[contactDetailInfo setValue:contactInfo forKey:@​​​​"info"​​​​];​


​[contactInfo setValue:contactDetailInfo forKey:@​​​​"details"​​​​];​


 


​NSError *error;​


​if​​​​(![context save:&error])​


​{​


​NSLog(@​​​​"不能保存:%@"​​​​,[error localizedDescription]);​


​}​


​}​



创建数据上下文,调用insertNewObjectForName方法,创建两个数据记录NSManagedObject,然后就可以对之前数据模型编辑视图中定义的属性进行赋值。此时的数据只在内存中被修改,最后调用数据上下文的save方法,保存到持久层

4.查询数据

在调用了insertCoreData之后,可以调用自定的查询方法dataFetchRequest来查询插入的数据




​?​



1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17




​- (​​​​void​​​​)dataFetchRequest​


​{​


​NSManagedObjectContext *context = [self managedObjectContext];​


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


​NSEntityDescription *entity = [NSEntityDescription entityForName:@​​​​"ContactInfo"​​ ​​inManagedObjectContext:context];​


​[fetchRequest setEntity:entity];​


​NSError *error;​


​NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];​


​for​​ ​​(NSManagedObject *info in fetchedObjects) {​


​NSLog(@​​​​"name:%@"​​​​, [info valueForKey:@​​​​"name"​​​​]);​


​NSLog(@​​​​"age:%@"​​​​, [info valueForKey:@​​​​"age"​​​​]);​


​NSLog(@​​​​"birthday:%@"​​​​, [info valueForKey:@​​​​"birthday"​​​​]);​


​NSManagedObject *details = [info valueForKey:@​​​​"details"​​​​];​


​NSLog(@​​​​"address:%@"​​​​, [details valueForKey:@​​​​"address"​​​​]);​


​NSLog(@​​​​"telephone:%@"​​​​, [details valueForKey:@​​​​"telephone"​​​​]);​


​}​


​}​



fetchRequest相当于sql查询语句的包装类,需要用setEntity方法,来指定具体查询的实体结构(表结构)

通过NSEntityDescription的entityForName方法来,返回指向该具体实体结构的指针

然后调用executeFetchRequest:error:方法,来执行查询操作,如果操作成功,则返回对应的数据记录数组

其中,可以通过NSManagedObject数据记录对象里关联的属性,查询另一个数据记录对象里的属性

5.数据模版

为每个实体生成一个NSManagedObject子类

上面设置数据和获取数据时,使用的是Key-Value方式,更好的方法是通过生成强类型的NSManagedObject的子类,通过类的成员属性来访问和获取数据

(1)在数据编辑器视图中选中实体对象,

选则file菜单,点击new,点击file...,选择Core Data项,选择NSManagedObject subclass,生成该实体同名的类,

继承于NSManagedObject

Core Data (2)-备用_数据模型_17

生成对应的ContactInfo.h文件




​?​



1


2


3


4


5


6


7


8


9


10


11


12


13




​#import <Foundation/Foundation.h>​


​#import <CoreData/CoreData.h>​


 


​@​​​​class​​ ​​ContactDetailInfo;​


 


​@interface ContactInfo : NSManagedObject​


 


​@property (nonatomic, retain) NSString * age;​


​@property (nonatomic, retain) NSString * birthday;​


​@property (nonatomic, retain) NSString * name;​


​@property (nonatomic, retain) ContactDetailInfo *details;​


 


​@end​



和ContactInfo.m文件

其中,@dynamic告诉编译器不做处理,使编译通过,其getter和setter方法会在运行时动态创建,由Core Data框架为此类属性生成存取方法




​?​



1


2


3


4


5


6


7


8


9


10


11


12




​#import "ContactInfo.h"​


​#import "ContactDetailInfo.h"​


 


 


​@implementation ContactInfo​


 


​@dynamic age;​


​@dynamic birthday;​


​@dynamic name;​


​@dynamic details;​


 


​@end​



以及ContactDetailInfo.h文件




​?​



1


2


3


4


5


6


7


8


9


10


11


12


13




​#import <Foundation/Foundation.h>​


​#import <CoreData/CoreData.h>​


 


​@​​​​class​​ ​​ContactInfo;​


 


​@interface ContactDetailInfo : NSManagedObject​


 


​@property (nonatomic, retain) NSString * address;​


​@property (nonatomic, retain) NSString * name;​


​@property (nonatomic, retain) NSString * telephone;​


​@property (nonatomic, retain) ContactInfo *info;​


 


​@end​



和ContactDetailInfo.m文件




​?​



1


2


3


4


5


6


7


8


9


10


11


12




​#import "ContactDetailInfo.h"​


​#import "ContactInfo.h"​


 


 


​@implementation ContactDetailInfo​


 


​@dynamic address;​


​@dynamic name;​


​@dynamic telephone;​


​@dynamic info;​


 


​@end​



此时,数据模型编辑器视图最右边栏中,实体的class就变成具体的类名

Core Data (2)-备用_数据模型_18

之前用Key-Value的代码就可以修改为:




​?​



1


2




​#import "ContactInfo.h"​


​#import "ContactDetailInfo.h"​





​?​



1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19


20


21


22


23




​- (​​​​void​​​​)insertCoreData​


​{​


​NSManagedObjectContext *context = [self managedObjectContext];​


 


​ContactInfo *contactInfo = [NSEntityDescription insertNewObjectForEntityForName:@​​​​"ContactInfo"​​ ​​inManagedObjectContext:context];​


​contactInfo.name = @​​​​"name B"​​​​;​


​contactInfo.birthday = @​​​​"birthday B"​​​​;​


​contactInfo.age = @​​​​"age B"​​​​;​


 


​ContactDetailInfo *contactDetailInfo = [NSEntityDescription insertNewObjectForEntityForName:@​​​​"ContactDetailInfo"​​ ​​inManagedObjectContext:context];​


​contactDetailInfo.address = @​​​​"address B"​​​​;​


​contactDetailInfo.name = @​​​​"name B"​​​​;​


​contactDetailInfo.telephone = @​​​​"telephone B"​​​​;​


 


​contactDetailInfo.info = contactInfo;​


​contactInfo.details = contactDetailInfo;​


 


​NSError *error;​


​if​​​​(![context save:&error])​


​{​


​NSLog(@​​​​"不能保存:%@"​​​​,[error localizedDescription]);​


​}​


​}​





​?​



1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18




​- (​​​​void​​​​)dataFetchRequest​


​{​


​NSManagedObjectContext *context = [self managedObjectContext];​


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


​NSEntityDescription *entity = [NSEntityDescription entityForName:@​​​​"ContactInfo"​​ ​​inManagedObjectContext:context];​


​[fetchRequest setEntity:entity];​


​NSError *error;​


​NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];​


​for​​ ​​(ContactInfo *info in fetchedObjects) {​


 


​NSLog(@​​​​"name:%@"​​​​, info.name);​


​NSLog(@​​​​"age:%@"​​​​, info.age);​


​NSLog(@​​​​"birthday:%@"​​​​, info.birthday);​


​ContactDetailInfo *details = info.details;​


​NSLog(@​​​​"address:%@"​​​​, details.address);​


​NSLog(@​​​​"telephone:%@"​​​​, details.telephone);​


​}​


​}​



三、数据库相关

1.打印隐藏的sql语句:

在Edit Scheme中选择Run,之后进入Arguments标签,添加参数:“-com.apple.CoreData.SQLDebug 1”

2.使用SQLite存储时,数据库结构

存储的SQLite数据库表名称:大写“Z”加上实体名称大写,一个实体相当于一张表

具体的字段名称:大写“Z”加上实体属性名称大写

Core Data (2)-备用_数据模型_19