数据持久化(五)之CoreData

最后更新于:2022-04-01 22:58:49

@简单的说,Core Data就是可以存储到磁盘的对象图,[...]Core Data可以帮我们做很多任务作.它可以作为软件的整个模型层。它不仅仅在磁盘上存储数据,也把我们需要的数据对象读取到内存中。                                                                                                                               ——Marcus Zarra, Core Data @Core Data是Mac OS X中Cocoa API的一部分,首次在Mac OS X 10.4 Tiger与iOS 3.0系统中出现[2]。它允许按照实体-属性-值模型组织数据,并以XML,二进制文件或SQLite数据文件的格式将其串行化。Core Data允许用户使用代表实体和实体间关系的高层对象来操作数据。它也可以管理串行化的数据,提供对象生存期管理与object graph管理,包括存储。Core Data直接与SQLite交互,避免开发者使用原本的SQL语句,就像Cocoa绑定在模型-视图-控制器设计中做了很多控制器的工作一样,Core Data做了很多数据模型的工作。它的主要任务是负责数据更改的管理,串行化到磁盘,最小化内存占用,以及查询数据。 @http://www.cocoachina.com/iphonedev/sdk/2010/1126/2397.html( 这是官方对于CoreData的说明) @接下来,我就不利用框架自动生成代码,完全自己编写所有的 Core data 相关代码的命令行应用程序来深入讲解 Core data的使用。 ***概念图*** ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569358ad9eab5.jpg) @添加CoreData框架,导入#import 写代码之前需要了解6个对象: (1)NSManagedObjectContext(被管理的数据上下文) 操作实际内容(操作持久层) 作用:插入数据,查询数据,删除数据 (2)NSManagedObjectModel(被管理的数据模型) 数据库所有表格或数据结构,包含各实体的定义信息 作用:添加实体的属性,建立属性之间的关系 操作方法:视图编辑器,或代码 (3)NSPersistentStoreCoordinator(持久化存储助理) 相当于数据库的连接器 作用:设置数据存储的名字,位置,存储方式,和存储时机 (4)NSManagedObject(被管理的数据记录) 相当于数据库中的表格记录 (5)NSFetchRequest(获取数据的请求) 相当于查询语句 (6)NSEntityDescription(实体结构) 相当于表格结构 (7)后缀为.xcdatamodeld的包 里面是.xcdatamodel文件,用数据模型编辑器编辑 编译后为.momd或.mom文件 1.自定义封装的CoreData管理类**HMTCoreDataManager** **.h** ~~~ #import #import /** * 数据存储成功的代码块 */ typedef void(^HandleSaveSuccessedBlock)(); /** * 数据存储失败的代码块 */ typedef void(^HandleSaveFailedBlock)(NSError *); @interface HMTCoreDataManager : NSObject @property (nonatomic,strong)NSManagedObjectContext *managedObjectContext; // 托管对象上下文 /** * 创建一个单例对象 * * @return 单例对象 */ + (HMTCoreDataManager *)defaultManager; /** * 根据实体描述获得托管对象 * * @param entityName 指定实体描述名字 * @param aClass 要获取的托管对象 * * @return 托管对象实例 */ - (NSManagedObject *)managedObjectWithEntityName:(NSString *)entityName managedObjectClass:(Class)aClass; /** * 数据存储到磁盘中成功和失败响应的方法,参数为2个block * * @param aSuccessedHandler * @param aFailedHandler */ - (void)saveWithSuccessedHandler:(HandleSaveSuccessedBlock)aSuccessedHandler failedHandler:(HandleSaveFailedBlock)aFailedHandler; //  插入数据 - (void)insertCoreData; //  查询 - (NSMutableArray*)selectData:(NSString *)name; //  删除 - (void)deleteData:(NSManagedObject *)object; //  更新 - (void)updateData:(NSString* )newName; @end ~~~ .m ~~~ #import "HMTCoreDataManager.h" @interface HMTCoreDataManager () @property (nonatomic,strong) NSPersistentStoreCoordinator *persistentStoreCoordinator; // 持久化存储协调器 @property (nonatomic,strong) NSManagedObjectModel * managedObjectModel; // 托管对象模型 @end @implementation HMTCoreDataManager static HMTCoreDataManager *manager = nil; + (HMTCoreDataManager *)defaultManager{ @synchronized(self){ if (manager == nil) { manager = [[HMTCoreDataManager alloc] init]; } } /* // 通过GCD创建 static dispatch_once_t onceToken; dispatch_once(&onceToken,^{ manager = [[HMTCoreDataManager alloc] init]; }); */ return manager; } #pragma mark - 属性的方便之处能在get方法中初始化 /** * 很多人对于这个上下文不太理解,开始我也不太理解,查了很多资料,感觉下面这个解释比较通俗易懂 * 托管对象上下文: * 托管对象上下文包含所有的托管对象,这些托管对象已经为提交给数据库准备就绪,在托管对象上下文中,可以添加、修改和删除托管对象, * 这一层相当于应用程序和数据库之间的缓冲区。 */ - (NSManagedObjectContext *)managedObjectContext{ if (_managedObjectContext) { return _managedObjectContext; } _managedObjectContext = [[NSManagedObjectContext alloc] init]; // 为托管对象上下文指定一个持久化存储协调器 [_managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator]; return _managedObjectContext; } /** * 持久化存储协调器(持久化存储助理) * 持久化存储协调器处理到数据存储的连接,并且包含一些底层信息,像用到数据存储的名字和位置 * 一般我们无需与它直接打交道,上下文已经封装了对它的调用 */ - (NSPersistentStoreCoordinator *)persistentStoreCoordinator{ if (_persistentStoreCoordinator) { return _persistentStoreCoordinator; } // 初始化一个持久化存储协调器必须依赖NSManagedObjectModel _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel]; // 存储路径(返回的是NSURL类型)为Documents目录下,以及数据库名称 NSURL *documentURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; NSURL *fileURL = [documentURL URLByAppendingPathComponent:@"myClass.sqlite"]; NSError *error = nil; // 加载持久化存储数据(指定持久化存储的数据类型,默认的是NSSQLiteStoreType,即SQLite数据库) [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:fileURL options:nil error:&error]; if (error != nil) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"添加持久化存储失败" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; [alert show]; } return _persistentStoreCoordinator; } /** * 托管对象模型 * 数据库所有表格或数据结构包含各实体的定义信息 * 添加实体的属性,建立属性之间的关系 */ - (NSManagedObjectModel *)managedObjectModel{ if (_managedObjectModel) { return _managedObjectModel; } // 获取托管对象模型文件的地址 // 编译器会自动将"xcdatamodeld"格式转化为"momd" NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"myClassModel" withExtension:@"momd"]; _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return _managedObjectModel; } - (NSManagedObject *)managedObjectWithEntityName:(NSString *)entityName managedObjectClass:(Class)aClass{ // 创建"HMTClass"的实体描述 NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"HMTClassEntity" inManagedObjectContext:self.managedObjectContext]; // 通过"HMTClass"的实体描述创建HMTClass的托管对象 NSManagedObject *managedObject = [[aClass alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:self.managedObjectContext]; return managedObject; } - (void)saveWithSuccessedHandler:(HandleSaveSuccessedBlock)aSuccessedHandler failedHandler:(HandleSaveFailedBlock)aFailedHandler{ NSError *error = nil; [self.managedObjectContext save:&error]; if (error != nil) { aFailedHandler(error); }else { aSuccessedHandler(); } } @end ~~~ 2.创建模型文件**ManagedObject****的过程** **![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569358adb7098.jpg) ** ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569358adf2441.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569358ae4fac9.jpg) 3.将创建的模型文件转化为对应的类文件 第一种:command+n ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569358ae757f5.jpg) 第二种: 选中myClassModel.xcdatamodeld![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569358aebf3ea.jpg) 之后都是一样的--->选中模型文件--->选中要创建的实体 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569358aed8340.jpg)![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_569358af1a6cd.jpg) 最后,就会生成前面图片中的3个类,都是继承了NSManagedObject ~~~ ------------------class------------------------------- @class HMTStudent, HMTTeacher; @interface HMTClass : NSManagedObject @property (nonatomic, retain) NSString * name; @property (nonatomic, retain) NSSet *students; @property (nonatomic, retain) HMTTeacher *teacher; @end @interface HMTClass (CoreDataGeneratedAccessors) - (void)addStudentsObject:(HMTStudent *)value; - (void)removeStudentsObject:(HMTStudent *)value; - (void)addStudents:(NSSet *)values; - (void)removeStudents:(NSSet *)values; @end #import "HMTClass.h" #import "HMTStudent.h" #import "HMTTeacher.h" @implementation HMTClass @dynamic name; @dynamic students; @dynamic teacher; @end ------------------teacher------------------------------- @class HMTClass; @interface HMTTeacher : NSManagedObject @property (nonatomic, retain) NSString * name; @property (nonatomic, retain) NSString * course; @property (nonatomic, retain) HMTClass *myClass; @end #import "HMTTeacher.h" #import "HMTClass.h" @implementation HMTTeacher @dynamic name; @dynamic course; @dynamic myClass; @end ------------------student------------------------------- @class HMTClass, HMTTeacher; @interface HMTStudent : NSManagedObject @property (nonatomic, retain) NSString * name; @property (nonatomic, retain) NSNumber * age; @property (nonatomic, retain) HMTTeacher *teacher; @property (nonatomic, retain) HMTClass *myClass; @end #import "HMTStudent.h" #import "HMTClass.h" #import "HMTTeacher.h" @implementation HMTStudent @dynamic name; @dynamic age; @dynamic teacher; @dynamic myClass; @end ~~~ 4.准备工作都OK了,最后进行数据的持久化存储 ~~~ #pragma mark - 增删改查 // 插入数据操作(类似于FMDB做法,方法后面可带你想存储的数据对象,这里只是单纯的演示) // - (void)insertCoreData:(AppleClass *)appleClass - (void)insertCoreData{ // 创建"HMTClass"的实体描述,传入的正是前面标注的实体描述名 NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"HMTClassEntity" inManagedObjectContext:self.managedObjectContext]; // 通过"HMTClass"的实体描述创建HMTClass的托管对象 HMTClass *hmtClass = [[HMTClass alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:self.managedObjectContext]; // hmtClass.name = appleClass.name; hmtClass.name = @"Apple"; // 托管对象上下文将托管对象的更改保存到磁盘文件中 // - save 将数据保存到数据库 NSError *error = nil; [self.managedObjectContext save:&error]; if (error != nil) { NSLog(@"添加失败:%@",[error localizedDescription]); } } // 删除数据操作 - (void)deleteData:(NSManagedObject *)object{ [self.managedObjectContext deleteObject:object]; NSError *error = nil; [[HMTCoreDataManager defaultManager].managedObjectContext save:&error]; if (error != nil) { NSLog(@"删除失败:%@",[error localizedDescription]); } } // 查询数据操作(依据特定条件查询,如果是select * 就直接不写谓词判断语句) - (NSMutableArray*)selectData:(NSString *)name{ // 创建指定Entity的查询语句 NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"HMTClassEntity"]; // 谓词,原理和用法都类似于SQL中的where,作用相当于数据库的过滤取(我blog中OC分类有具体讲到) NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"name == \'%@\'",name],nil]; fetchRequest.predicate = predicate; // 查询的结果按哪个key进行排序,YES为升序 // NSSortDescriptor *timestampSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"classNO" ascending:YES]; // fetchRequest.sortDescriptors = @[timestampSortDescriptor]; // 注意查询返回的只能是NSArray类型 NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil]; NSMutableArray *resultArray = [NSMutableArray arrayWithArray:fetchedObjects]; return resultArray; } // 更新数据操作 - (void)updateData:(NSString *)newName{ // 创建指定Entity的查询语句 NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"HMTClassEntity"]; // 注意查询返回的只能是NSArray类型 NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil]; // 更新 for (HMTClass *info in fetchedObjects) { info.name = newName; } //保存 if ([self.managedObjectContext save:nil]) { //更新成功 NSLog(@"更新成功"); } } ~~~
';