Core Data是iOS5之后才出现的一个框架,它提供了对象-关系映射(ORM)的功能即能够将OC对象转化成数据,保存在SQLite数据库文件中,也能够将保存在数据库中的数据还原成OC对象。
传统的数据库要把数据写到数据库,而且要写SQL语句 Core Data 就避免了写SQL语句的麻烦了
CoreData底层的持久化存储方式可以是SQLite数据库,也可以是XML文件,甚至可以直接以内存作为持久化存储设备(如果选用该存储方式,那么应用重启时数据会丢失)。
CoreData的核心概念是实体。实体是由Core Data管理的模型对象,它必须是NSManagedObject类或其子类的实例。实体与实体之间存在1-1、1-N、N-N的关联关系。整个应用的所有实体以及实体之间的关联关系被称为托管对象模型。
CoreData的核心对象是托管对象上下文(NSManagedObjectContext,有时简称上下文),所有实体都处于托管对象上下文管理中,Core Data应用对实体所做的任何增、删、改、查操作都必须通过托管对象上下文来完成。
NSManagedObjectContext底层又与持久化存储协调器(NSPersistentStoreCoordinator)衔接。持久化存储协调器负责管理底层的存储形式,比如利用SQLite存储。
下面来总结Core Data中的核心API:
1. 实体(NSManagedObject):代表实体。实体必须是该类或该类的子类
2. 托管对象模型(NSManagedObjectModel):该对象负责管理整个应用的所有实体以及实体之间的关联关系。
3. 持久化存储协调器(NSpersistentStoreCoordinator):负责管理底层的存储方式,如利用SQLite存储。
4. 托管对象上下文(NSManagedObjectContext):对实体做的增、删、改、查操作都必须通过托管对象上下文来完成。
5. 实体描述(NSEntityDescription):该对象代表了关于某个实体的描述信息。从某种角度来说,该对象相当于实体的抽象。
6. 获取请求(NSfetchRequest):该对象封装了查询实体的请求,包括程序需要查询哪些实体、查询条件、排序规则等。
下面介绍一下使用Core Data的步骤:
1. 创建NSManageObjectModel对象来加载管理应用的托管对象模型。
2. 以NSManageObjectModel对象为基础,根据实际创建NSPersistentStoreCoordinator对象,该对象确定Core Data的底层存储形式。
3. 以NSManageObjectModel对象为基础,创建NSmanagedObjectContext对象,该对象是Core Data进行持久化访问的核心对象。
4. 利用获取实例(NSFectRequest)再调用NSmanagedObjectContext的executeFetchRequest:error:方法执行查询,找到符合条件的实体,再进行执行增、删、改、查操作,然后调用NSmanagedObjectContext对象的save:方法将修改白村到底层存储设备。
下面我们还是来通过存储学生信息为例,来讲解CoreData的简单使用。
新建项目,勾选Use Core Data复选框,我这里的项目名为:01-CoreData
create之后,会在项目导航区看到下图文件
还会在appDelegate类中发现多了几个属性和方法,如下:
appDelegate.h
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@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;
/**
* 获取Document的URL路径
*/
- (NSURL *)applicationDocumentsDirectory;
@end
appDelegate.m
#pragma mark - Core Data stack
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
/**
* 获取Document的URL路径
*/
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
/**
* 初始化托管对象模型(实体以及实体之间的关联关系)
*/
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
// 获取实体模型文件对应的URL
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"_1_CoreData" withExtension:@"momd"];
// 根据URL创建并初始化托管模型对象
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
/**
* 初始化持久化存储协调器(Core Data底层的存储形式)
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// 以托管模型对象创建并初始化协调器
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
// 获取SQlLite数据库的存储目录
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"_1_CoreData.sqlite"];
NSError *error = nil;
NSString *failureReason = @"There was an error creating or loading the application's saved data.";
// 设置底层数据存储机制为SQLite数据库,如果设置失败则返回错误信息
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.(设置错误信息)
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
/**
* 初始化托管对象上下文
*/
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
#pragma mark - Core Data Saving support
/**
* 保存上下文的修改
*/
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = nil;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
并且在应用的代理方法中有:(当应用退出后,会保存上下文的修改)
- (void)applicationWillTerminate:(UIApplication *)application {
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}
点击.xcodemodeld文件,在工作区会出现如图所示界面
点击左下角add Entity按钮添加实体
然后在ENTITIES区会出现如图所示实体,再重命名实体名,我这里重命名为:StudentEntity
在该实体的右侧会出现添加属性界面,点击添加属性
属性添加完之后,点击xcode导航栏上的Editor -> Create NSManageObject Subclass自动创建实体类,如下:
这些准备工作做好以后,我们就可以向数据库_1_CoreData.sqlite中进行数据的增、删、该、查操作了。
添加学生信息:
点击添加按钮,将学生信息插入数据库中(这里不考虑重复插入)
/**
* 添加学生信息
*/
- (IBAction)addClick {
// 利用NSEntityDescription获取StudentEntity实体
StudentEntity *stu = [NSEntityDescription insertNewObjectForEntityForName:@"StudentEntity" inManagedObjectContext:[AppDelegate shareAppDelegate].managedObjectContext];
stu.name = self.nameTextField.text;
stu.age = [NSNumber numberWithInteger:[self.ageTextField.text integerValue]];
stu.sex = [NSNumber numberWithInt:[self.sexTextField.text intValue]];
NSError *error = nil;
[[AppDelegate shareAppDelegate].managedObjectContext save:&error];
if (error) {
NSLog(@"添加失败");
}else {
NSLog(@"添加成功");
}
}
点击添加按钮后,会在应用沙盒中发现下图文件:
打印结果:
现在我们向数据库中多插入几条数据,然后来做查询操作,看看数据库中有没有数据。查询操作如下:
/**
* 查询所有学生信息,并打印
*/
- (IBAction)queryClick {
// 得到获取数据的请求对象
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"StudentEntity"];
// 排序规则(查询结果按年龄降序排序)
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
request.sortDescriptors = @[sort];
// 执行查询
NSError *error = nil;// 错误信息
NSArray *result = [[AppDelegate shareAppDelegate].managedObjectContext executeFetchRequest:request error:&error];
if (error) {
NSLog(@"查询操作失败");
}else {
if (result.count <= 0) {
NSLog(@"无学习信息");
}else {
NSLog(@"打印学生信息:");
for (StudentEntity *stu in result) {
NSLog(@"姓名:%@,年龄:%lu,性别:%d", stu.name, stu.age.integerValue, stu.sex.intValue);
}
}
}
}
打印出来看看,我们刚刚添加的多条学生信息
结果就是我们添加的学生,证明我们的数据已经添加到数据库中了。
我们先来删除指定姓名(如:shx1)的学生信息:(数据库中所有叫shx1的学生会全部删除)
/**
* 删除指定姓名的学生信息
*/
- (IBAction)deleteClick {
// 先遍历数据库,查询有无该学生信息,无该学生则不用执行删除操作
// 得到获取数据的请求对象
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"StudentEntity"];
// 查询条件
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", self.deleteNameTextField.text];
request.predicate = predicate;
// 排序规则(按年龄升序)
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
request.sortDescriptors = @[sort];
// 执行查询
NSError *error = nil;// 错误信息
NSArray *result = [[AppDelegate shareAppDelegate].managedObjectContext executeFetchRequest:request error:&error];
// 查询结果
if (error) {
NSLog(@"查询操作失败");
}else {
if (result.count) {// 有该学生信息,可执行删除操作
for (StudentEntity *stu in result) {
// 删除学生信息
[[AppDelegate shareAppDelegate].managedObjectContext deleteObject:stu];
NSLog(@"删除成功");
}
// 删除数据后,保存
NSError *saveError = nil;
[[AppDelegate shareAppDelegate].managedObjectContext save:&saveError];
if (saveError) {
NSLog(@"删除,保存失败");
}else {
NSLog(@"删除,保存成功");
}
}else {
NSLog(@"无该学生信息");
}
}
}
输入要删除的学生姓名:shx1打印结果:
我们再查询所有学生信息,并打印,看看shx1还在不在,点击查询:
姓名叫shx1的学生没有了,证明我们已经删除了。
现在我们来修改某个学生(比如:shx5)的年龄。(原shx5的年龄从上面指定为22,现在我们将他的年龄改为100,数据库中所有叫shx5的学生的年龄都会被改成100)。
/**
* 修改某个学生的年龄
*/
- (IBAction)tureClick {
// 先遍历数据库,查询有无该学生信息,无该学生则不能修改年龄
// 得到获取数据的请求对象
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"StudentEntity"];
// 查询条件
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", self.updateNameTextField.text];
request.predicate = predicate;
// 执行查询
NSError *error = nil;// 错误信息
NSArray *result = [[AppDelegate shareAppDelegate].managedObjectContext executeFetchRequest:request error:&error];
// 查询结果
if (error) {
NSLog(@"查询操作失败");
}else {
if (result.count) {// 有该学生信息,可执行修改操作
for (StudentEntity *stu in result) {
// 修改学生信息
stu.age = [NSNumber numberWithInt:self.updateAgeTextField.text.intValue];
NSLog(@"修改成功");
}
// 删除数据后,保存
NSError *saveError = nil;
[[AppDelegate shareAppDelegate].managedObjectContext save:&saveError];
if (saveError) {
NSLog(@"修改,保存失败");
}else {
NSLog(@"修改,保存成功");
}
}else {
NSLog(@"无该学生信息");
}
}
}
姓名输入shx5,年龄输入100,打印结果:
我们查询所有的学生信息,并打印出来,看看shx5的年龄是不是100。
姓名叫shx5的学生的年龄已经改为100了,证明我们的数据库操作是正确的。
以上是关于Core Data的简单使用,更进一步的使用我也在学习中。