您的位置:首页 > 移动开发 > IOS开发

iOS开发之Core Data数据存储

2015-12-14 15:31 666 查看
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的简单使用,更进一步的使用我也在学习中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: