iOS学习37数据处理之CoreData

1. CoreData数据库框架的优势

 1> CoreData历史

  CoreData数据持久化框架是Cocoa API 的一部分,首次在iOS5版本的系统中出现,它允许按照实体-属性-值模型组织数据,并以XML二级制文件或者SQLite数据文件的格式持久化数据。

  CoreData主要提供对象 --- 关系映射(ORM)功能,把OC对象转化为数据保存到文件,也可以数据转化为OC对象。

 2> CoreData数据库与Sqlite数据库的比较

  Sqlite

  • 基于C接口,需要使用sql语句,但是代码较为繁琐

  • 在处理大量数据时,表关系更为直观

  • 在OC中不是可视化的

  • 可以跨平台使用(iOS和安卓)

  CoreData:

  • 可视化,有undo/redo能力

  • 可以实现多种文件格式NSSQLiteStoreTypeNSBinaryStoreTypeNSInMemoryStoreTypeNSXMLStoreType

  • 苹果官方API支持,与iOS结合更紧密

  • 不能跨平台使用,只支持iOS

 3> CoreData核心对象及关系实例(以一个餐馆为例)

  

2. CoreData数据库框架的核心对象

 1> 被管理对象上下文(NSManagedObjectContext)

  NSManagedObjectContext:被管理对象上下文,CoreData中用于操作和使用数据,负责应用和数据库之间的交互,可以进行增、删、改、查

  数据的保存需要 NSManagedObjectContext 进行 save 操作

  数据的查询需要 NSManagedObjectContext 进行 executeFetchRequest 操作(返回值是数组)

  CoreData提供的是对象关系映射,NSManagedObjectContext操作的都是NSManagedObject对象

 2> 被管理对象相关类

  NSManagedObjectModel:被管理对象模型,管理多个对象

  NSManagedObject:被管理对象,CoreData返回的数据类型,被管理的对象是根据是根据实体描述生成的

  NSEntityDescription:实体描述类,根据实体创建被管理对象,可以映射出对象

  Entity:实体类,实体是对文件数据的描述。被管理对象表示实体,实体包含名称,属性(字段)和关系,实体的名称通常和被管理对象名一致

 3> 持久化存储和存储文件

  数据连接器类:NSPersistentStoreCoordinator,持久化存储调节器,它想要去SQLite数据库中拿数据必须通过NSPersistentStore

  NSPersistentStore:持久化存储,是对实际文件的一种。Objective-C表示方式,一个被封装好的底层类,用于存储数据

  存储文件:用来存储和管理数据的文件,iOS支持4种存储类型:NSSQLiteStoreType、NSBinaryStoreType、NSInMemoryStoreType、NSXMLStoreType

 4> 数据查询

  NSFetchRequest:查询请求,可以做排序操作,也可以使用谓词

  NSManagedObjectModel根据NSFetchRequest查询数据,以数组形式返回,数组中包含被管理对象(NSManagedObject

  NSSortDescriptor:排序操作

3. CoreData数据库的简单操作 

 1> 创建步骤

  ① 创建带有CoreData数据库的工程

  

  ② 创建实体类与属性

  ③ 切换可视化关系图

   

  ④ 创建实例类

    

 2> CoreData上下文(NSManagedObjectContext)的创建

  创建NSManagedObjectContext 这个类的对象 一般都用从AppDelegate里面的拿过来用,不用单独创建,创建工程勾选 use CoreData 这些代码AppDelegate就创建好

 1 @interface ViewController ()
 2 
 3 #pragma mark - 第二步:声明属性【声明管理对象上下文】(Sqlite中是声明一个存储数据路径的属性)
 4 @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
 5 
 6 @end
 7 
 8 @implementation ViewController
 9 
10 #pragma mark - 懒加载(与以前有所区别)
11 - (NSManagedObjectContext *)managedObjectContext
12 {
13     // 因为在Appdelegate中已经实现过了,所以这里是从Appdelegate中去获取
14     if (!_managedObjectContext) {
15         
16         // 获取appDelegate对象,使用系统的单例方法创建
17         AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
18         
19         _managedObjectContext = appDelegate.managedObjectContext;
20     }
21     return _managedObjectContext;
22 }
23 
24 @end

 3> AppDelegate创建好的代码解析(详解请看注释)

  AppDelegate.h

 1 #import <UIKit/UIKit.h>
 2 #import <CoreData/CoreData.h>
 3 
 4 @interface AppDelegate : UIResponder <UIApplicationDelegate>
 5 
 6 @property (strong, nonatomic) UIWindow *window;
 7 
 8 /// 管理数据库上下文的对象,可以进行增、删、改、查
 9 @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
10 
11 /// 管理数据库中的对象(对象模型),可以将工程中的对象合并(为了更加方便的生成数据库中的表)
12 @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
13 
14 /// 数据库持久化协调器,实际的工作都是由它来做的
15 @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
16 
17 - (void)saveContext;
18 - (NSURL *)applicationDocumentsDirectory;
19 
20 @end

  AppDelegate.m

  1 #import "AppDelegate.h"
  2 
  3 @interface AppDelegate ()
  4 
  5 @end
  6 
  7 @implementation AppDelegate
  8 
  9 #pragma mark - Core Data stack
 10 
 11 @synthesize managedObjectContext = _managedObjectContext;
 12 @synthesize managedObjectModel = _managedObjectModel;
 13 @synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
 14 
 15 // 返回coreData存储的路径
 16 - (NSURL *)applicationDocumentsDirectory {
 17     
 18     // 5. 打印coreData存储的路径【Sqlite的dbPath字符串路径】
 19     NSLog(@"filePath = %@", [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]);
 20     
 21     // 返回coreData存储的路径
 22     return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
 23 }
 24 
 25 #pragma mark - 获取管理对象
 26 - (NSManagedObjectModel *)managedObjectModel {
 27     
 28     if (_managedObjectModel != nil) {
 29         return _managedObjectModel;
 30     }
 31     
 32     // 从应用程序中加载模型文件
 33     // momd 是编译后的文件后缀
 34     NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"UISenior_4_1_CoreData" withExtension:@"momd"];
 35     
 36     _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];// 代表的就是刚刚创建的实体
 37     
 38     return _managedObjectModel;
 39 }
 40 
 41 #pragma mark - 数据持久化协调器(真正干活的)
 42 // persistentStoreCoordinator的getter方法
 43 - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
 44     
 45     if (_persistentStoreCoordinator != nil) {
 46         return _persistentStoreCoordinator;
 47     }
 48 
 49     // 连接器对象关联的实体模型
 50     _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
 51     
 52     // 定义数据存储的路径
 53     NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"UISenior_4_1_CoreData.sqlite"];
 54     
 55     NSError *error = nil;
 56     NSString *failureReason = @"There was an error creating or loading the application's saved data.";
 57     
 58     // NSSQLiteStoreType这个参数决定文件存储的形式(sqlite、XML、二进制等)
 59     if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
 60         // 返回可能出现的错误信息
 61         NSMutableDictionary *dict = [NSMutableDictionary dictionary];
 62         dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
 63         dict[NSLocalizedFailureReasonErrorKey] = failureReason;
 64         dict[NSUnderlyingErrorKey] = error;
 65         error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
 66 
 67         // abort()会导致应用程序生成一个崩溃日志和终止。虽然它可能是有用的在开发过程中, 但是你不应该使用这个函数在运行的应用程序中。
 68         NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
 69         abort();
 70     }
 71     
 72     return _persistentStoreCoordinator;
 73 }
 74 
 75 #pragma mark - 获取数据库上下文
 76 // managedObjectContext的getter方法
 77 - (NSManagedObjectContext *)managedObjectContext {
 78     
 79     if (_managedObjectContext != nil) {
 80         return _managedObjectContext;
 81     }
 82     
 83     // 创建数据持久化协调器
 84     NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
 85     
 86     if (!coordinator) {
 87         return nil;
 88     }
 89     
 90     // 创建managedObjectContext对象
 91     // ConcurrencyType 并发类型,是一个枚举值
 92     // NSMainQueueConcurrencyType 主队列并发类型(2)
 93     // NSPrivateQueueConcurrencyType 私有队列并发类型(1)
 94     // NSConfinementConcurrencyType 限制并发类型(0)
 95     _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
 96     
 97     // 数据连接器 关联 被管理上下文
 98     [_managedObjectContext setPersistentStoreCoordinator:coordinator];
 99     
100     return _managedObjectContext;
101 }
102 
103 #pragma mark - Core Data Saving support
104 
105 - (void)saveContext {
106     NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
107     if (managedObjectContext != nil) {
108         // 同上面的错误处理
109         NSError *error = nil;
110         if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
111             
112             NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
113             abort();
114         }
115     }
116 }
117 
118 @end

 4> 添加对象(详解请看注释)

 1 - (void)addPerson
 2 {
 3     // 添加的步骤
 4     // 1. 创建Person实体对象,然后开始"context",让它做好准备,将这个对象添加到数据库
 5     
 6     /**
 7      *  实例对象有两种[初始化实体对象需要借用NSEntityDescription]
 8      */
 9     
10     // 第一种:
11 //    Person *per = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.managedObjectContext];
12     // 第二种:
13     // 先创建一个实体
14     NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:self.managedObjectContext];
15     // 创建Person对象
16     Person *per = [[Person alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:self.managedObjectContext];
17     
18     // 2. 给对象属性赋值
19     per.personName = @"MBBoy";
20     per.personGender = @"Unkown";
21     per.personAge = @10;
22 
23     // 3. 将对象存入数据库
24     BOOL result = [_managedObjectContext save:nil];
25     
26     per.personCar = carSet;
27     
28     // 4. 判断是否插入成功(在AppDelegate中打印地址)
29     if (result) {
30         NSLog(@"添加数据成功");
31     } else {
32         NSLog(@"添加数据失败");
33     }
34 }

 5> 删除对象(详解请看注释)

 1 - (void)deletePerson
 2 {
 3     // 1. 实体化请求类【查询】
 4     NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
 5     
 6     // 2. 获取删除的条件(NSPredicate)
 7     request.predicate = [NSPredicate predicateWithFormat:@"personName = 'MBBoy'"];
 8     
 9     // 3. 由context根据删除条件的请求去具体进行删除操作
10     NSArray *resultArray = [self.managedObjectContext executeFetchRequest:request error:nil];
11     
12     // 为了代码的严密需要判断resultArray中是否有值
13     if (0 == resultArray.count) {
14         NSLog(@"未找到删除对象");
15     } else {
16         // 4. 遍历搜索出来结果
17         for (Person *per in resultArray) {
18             // 删除查询到相关的人的信息
19             [self.managedObjectContext deleteObject:per];
20         }
21         
22         // 5. 进行删除结果的判断,保存后删除操作才会写入文件
23         BOOL result = [_managedObjectContext save:nil];
24         if (result) {
25             NSLog(@"删除数据成功");
26         } else {
27             NSLog(@"删除数据失败");
28         }
29     }
30 }

 6> 更改对象(详解请看注释)

 1 - (void)updatePerson
 2 {
 3     // 1. 实体化请求类【查询】
 4     NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
 5     
 6     // 2. 设置查询的条件
 7     request.predicate = [NSPredicate predicateWithFormat:@"personName = 'MBBoy'"];
 8     
 9     // 3. 由context根据查询条件的请求去具体进行更新操作
10     NSArray *resultArray = [self.managedObjectContext executeFetchRequest:request error:nil];
11     
12     // 为了代码的严密需要判断resultArray中是否有值
13     if (0 == resultArray.count) {
14         NSLog(@"未找到更改对象,请检查谓词条件!");
15     } else {
16         // 4. 遍历搜索结果
17         for (Person *per in resultArray) {
18             
19             // 更新查询到相关的人的信息
20             per.personName = @"小强";
21             per.personGender = @"卵男";
22             per.personAge = @38;
23         }
24         
25         // 5. 进行删除结果的判断
26         BOOL result = [_managedObjectContext save:nil];
27         if (result) {
28             NSLog(@"更改数据成功");
29         } else {
30             NSLog(@"更改数据失败");
31         }
32     }
33 }

 7> 查询对象(详解请看注释)

 1 - (void)selectPerson
 2 {
 3     // 1. 实体化请求类【查询】
 4     NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
 5     
 6     // 2. 设置查询的条件
 7     request.predicate = [NSPredicate predicateWithFormat:@"personName like '*B*'"];
 8     
 9     // 3. 根据管理对象上下文执行相关的操作
10     NSArray *resultArray = [self.managedObjectContext executeFetchRequest:request error:nil];
11     
12     if (0 == resultArray.count) {
13         NSLog(@"未找到查询对象,请检查谓词条件!");
14     } else {
15         for (Person *per in resultArray) {
16             NSLog(@"name = %@, gender = %@, age = %@", per.personName, per.personGender, per.personAge);
17         }
18     }
19 }

  补: 查询结果的排序

1     // 设置排序方式
2     NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"address" ascending:NO];
3     request.sortDescriptors = @[sort];

4. CoreData数据库表关联操作 

 1> 添加表关系可视化操作

  Car数据库与Person数据库建立关联:

  

 Person数据库与Car数据库建立关联: