一、CoreData的简单理解
CoreData
是一个模型层的技术,也是一种持久化技术,它能将模型对象的状态持久化到磁盘里,我们不需要使用SQL
语句就能对它进行操作。CoreData
不是一个数据库但是可以使用数据库来存储数据,也可以使用其他方式,比如:数据库文件
,XML
,二进制文件
,内存
等。CoreData
提供了对象-关系映射(ORM)
功能。能够实现数据库数据和OC
对象的相互转换,在这个转换过程中我们不需要编写任何SQL
语句。为什么要使用
CoreData
极大的减少Model
层的代码量
优化了使用SQLite
时候的性能
提供了可视化设计
二、CoreData的使用
1、创建步骤
- 如果你是一个新的项目,可以创建项目的时候选择
CoreData
如图
- 如果是老的项目之前没有使用
CoreData
,则按照如下的步骤:
第一步:先创建.xcdatamodeld
文件(右键 -> New File -> iOS -> Core Data ->Data Model)
第二步:命名然后创建(这里的名字要在后面操作的时候使用,要命好名字)
成功
2、创建CodeDataMode
实体,并在实体中添加我们需要的键值如图
3、创建实体关联文件
-
自动创建实体关联文件
创建好实体对象XXX.xcdatamodeld
之后,右侧属性栏Code Generation
下面的Language
默认为Swift
,这里使用OC
,就改成Objective-C
;Codegen
默认为Class Definition
,无需更改。通过Xcode
的Build
会自动生成对应的实体关联文件,但是这些文件不会在目录中显示出来,对应的格式为:
//格式
实体名(表名)+CoreDataClass.h
实体名(表名)+CoreDataClass.m
实体名(表名)+CoreDataProperties.h
实体名(表名)+CoreDataProperties.m
//例如,实体名(表名)为Video,对应的关联文件为:
CoreDataMode+CoreDataClass.h
CoreDataMode+CoreDataClass.m
CoreDataMode+CoreDataProperties.h
CoreDataMode+CoreDataProperties.m
使用对应的实体时,导入对应的头文件即可,例如:
#import "CoreDataMode+CoreDataProperties.h"
-
手动创建实体关联文件
实体对象XXX.xcdatamodeld
里面的Codegen
一定得设置为Manual/None
,否则报文件重复错误,选中实体,点击Editor
,点击Create NSManagedObject Subclass…
生成实体关联文件:
手动创建好关联文件之后,目录如下图所示,用的时候导入对应的Properties
头文件即可:
4 、使用相应的类
-
NSManagedObjectContext
数据库操作:NSManagedObjectContext
被管理的对象上下文(对数据直接操作)
NSManagedObjectContext
:等同于一个容器,用来存储从数据库中转换出来的所有的OC
对象。我们的增删改查操作直接对这个类使用来获得或者修改需要的OC
对象,它能够调用NSPersistentStoreCoordinator
类实现对数据库的同步,这个对象有点像SQLite
对象(用来管理.xcdatamodeld
中的数据)。
负责数据和应用库之间的交互(CRUD
,即增删改查、保存等接口都是用这个对象调用)。
每个NSManagedObjectContext
和其他NSManagedObjectContext
都是完全独立的。
所有的NSManagedObject
(个人理解:实体数据)都存在于NSManagedObjectContext
中。
每个NSManagedObjectContext
都知道自己管理着哪些NSManagedObject
(实体数据)
可以通过TA去访问底层的框架对象集合,这些对象集合统称为持久化堆栈(persistence stack)
——它在应用程序和外部数据存储的对象之间提供访问通道
-
NSManagedObject
NSManagedObject
的工作模式有点类似于NSDictionary
对象,通过键-值对来存取所有的实体属性。NSManagedObject
:数据库中的数据转换而来的OC
对象
setValue:forkey
:存储属性值(属性名为key
);
valueForKey
:获取属性值(属性名为key
)。
每个NSManagedObject
都知道自己属于哪个NSManagedObjectContext
用于插入数据使用:获得实体,改变实体各个属性值,保存后就代表插入
-
NSEntityDescription
NSEntityDescription
用来描述实体(Entity
) 表格结构: 相当于数据库中的一个表,TA
描述一种抽象数据类型
通过Core Data
从数据库中取出的对象,默认情况下都是NSManagedObject
对象。
+insertNewObjectForEntityForName:inManagedObjectContext
: 工厂方法,根据给定的Entity
描述,生成相应的NSManagedObject
对象,并插入到ManagedObjectContext
中
LHModel * model = [NSEntityDescription insertNewObjectForEntityForName:@“CoreDataMode” inManagedObjectContext:self.managedObjectContext];
通过上面的代码可以得到model
这个表的实例,然后可以使用这个实例去为表中的属性赋值
model.title = @“标题”;
model.content = @“内容”;
-
NSPersistentStoreCoordinator
NSPersistentStoreCoordinator
持久化存储库,CoreData
的存储类型(比如SQLite
数据库就是其中一种)。
用来将对象管理部分和持久化部分捆绑在一起,负责相互之间的交流
用来设置CoreData
存储类型和存储路径
使用Core Data document
类型的应用程序,通常会从磁盘上的数据文中中读取或存储数据,这写底层的读写就由Persistent Store Coordinator
来处理。一 般我们无需与它直接打交道来读写文件,Managed Object Context
在背后已经为我们调用Persistent Store Coordinator
做了这部分工作
NSPersistentStoreCoordinator
:通过解析结果去实现数据库和OC
对象之间的相互转换,主要是操作数据库的,我们一般用不上,由系统处理
-
NSManagedObjectModel
NSManagedObjectModel Core Data
的模型文件,有点像SQLite的.sqlite
文件(个人理解:表示一个.xcdatamodeld
文件)应用程序的数据模型,数据库中所有表格和他们之间的联系
NSManagedObjectModel
:负责读取解析.momod
文件
NSManagedObjectModel * model = [self managedObjectModel];
//获取实例
NSDictionary * entities = [model entitiesByName];
//entitiesByName
得到所有的表的名字
NSEntityDescription * entity = [entities valueForKey:@“CoreDataModel”];
//从里面找出名为Student
的表
5、具体实现 创建CoreDataManager 类
CoreDataManager.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface CoreDataManager : NSObject
/**
* 上下文 容器
* 存放的是 所有从数据库中取出的转换成OC对象
*/
@property (strong, nonatomic) NSManagedObjectContext * managedObjectContext;
/* 读取解析 .momd文件中的内容 */
@property (strong, nonatomic) NSManagedObjectModel * managedObjectModel;
/* 连接的类,处理数据库数据和OC数据底层的相互转换 */
@property (strong, nonatomic) NSPersistentStoreCoordinator * persistentStoreCoordinator;
/**
单例
@return CoreDataManager
*/
+ (instancetype)sharedInstance;
/**
插入数据
@param dict 字典中的键值对必须要与实体中的每个名字一一对应
@param success 成功回调
@param fail 失败回调
*/
- (void)insertNewEntity:(NSDictionary *)dict success:(void(^)(void))success fail:(void(^)(NSError *error))fail;
/**
查询数据
@param selectKays 数组高级排序(数组里存放实体中的key,顺序按自己需要的先后存放即可),实体key来排序
@param isAscending 升序降序
@param filterString 查询条件
@param filterString 成功回调
@param fail 失败回调
*/
- (void)selectEntity:(NSArray *)selectKays ascending:(BOOL)isAscending filterString:(NSString *)filterString success:(void(^)(NSArray *results))success fail:(void(^)(NSError *error))fail;
/**
删除数据
@param model NSManagedObject
@param success 成功回调
@param fail 失败回调
*/
- (void)deleteEntity:(NSManagedObject *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail;
/**
更新数据
@param success 成功回调
@param fail 失败回调
*/
- (void)updateEntity:(void(^)(void))success fail:(void(^)(NSError *error))fail;
@end
CoreDataManager.m
#import "CoreDataManager.h"
//获取CoreData的.xcdatamodel文件的名称
static NSString * const coreDataModelName = @"CoreDataText";
//获取CodeData
static NSString * const coreDataEntityName = @"CoreDataMode";
//数据库
static NSString * const sqliteName = @"CoreDataMode.sqlite";
@interface CoreDataManager()
@end
@implementation CoreDataManager
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
static CoreDataManager *coreDataManager = nil;
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
coreDataManager = [[CoreDataManager alloc] init];
});
return coreDataManager;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (coreDataManager == nil) {
coreDataManager = [super allocWithZone:zone];
}
});
return coreDataManager;
}
- (void)insertNewEntity:(NSDictionary *)dict success:(void (^)(void))success fail:(void (^)(NSError *))fail {
if (!dict||dict.allKeys.count == 0) return;
// 通过传入上下文和实体名称,创建一个名称对应的实体对象(相当于数据库一组数据,其中含有多个字段)
NSManagedObject * entity = [NSEntityDescription insertNewObjectForEntityForName:coreDataEntityName inManagedObjectContext:self.managedObjectContext];
// 实体对象存储属性值(相当于数据库中将一个值存入对应字段)
for (NSString *key in [dict allKeys]) {
[entity setValue:[dict objectForKey:key] forKey:key];
}
// 保存信息,同步数据
NSError *error = nil;
BOOL result = [self.managedObjectContext save:&error];
if (!result) {
NSLog(@"添加数据失败:%@",error);
if (fail) {
fail(error);
}
} else {
NSLog(@"添加数据成功");
if (success) {
success();
}
}
}
- (void)deleteEntity:(NSManagedObject *)model success:(void (^)(void))success fail:(void (^)(NSError *))fail {
// 传入需要删除的实体对象
[self.managedObjectContext deleteObject:model];
// 同步到数据库
NSError *error = nil;
[self.managedObjectContext save:&error];
if (error) {
NSLog(@"删除失败:%@",error);
if (fail) {
fail(error);
}
} else {
NSLog(@"删除成功");
if (success) {
success();
}
}
}
- (void)selectEntity:(NSArray *)selectKays ascending:(BOOL)isAscending filterString:(NSString *)filterString success:(void (^)(NSArray *))success fail:(void (^)(NSError *))fail {
// 1.初始化一个查询请求
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// 2.设置要查询的实体
NSEntityDescription *desc = [NSEntityDescription entityForName:coreDataEntityName inManagedObjectContext:self.managedObjectContext];
request.entity = desc;
// 3.设置查询结果排序
if (selectKays&&selectKays.count>0) { // 如果进行了设置排序
NSMutableArray *array = [NSMutableArray array];
for (NSString *key in selectKays) {
/**
* 设置查询结果排序
* sequenceKey:根据某个属性(相当于数据库某个字段)来排序
* isAscending:是否升序
*/
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:key ascending:isAscending];
[array addObject:sort];
}
if (array.count>0) {
request.sortDescriptors = array;// 可以添加多个排序描述器,然后按顺序放进数组即可
}
}
// 4.设置条件过滤
if (filterString) { // 如果设置了过滤语句
NSPredicate *predicate = [NSPredicate predicateWithFormat:filterString];
request.predicate = predicate;
}
// 5.执行请求
NSError *error = nil;
NSArray *objs = [self.managedObjectContext executeFetchRequest:request error:&error]; // 获得查询数据数据集合
if (error) {
NSLog(@"失败");
if (fail) {
fail(error);
}
} else{
NSLog(@"成功");
if (success) {
success(objs);
}
}
}
- (void)updateEntity:(void (^)(void))success fail:(void (^)(NSError *))fail {
NSError *error = nil;
[self.managedObjectContext save:&error];
if (error) {
NSLog(@"删除失败:%@",error);
if (fail) {
fail(error);
}
} else {
if (success) {
success();
}
}
}
#pragma 懒加载
//managedObjectModel 属性的getter方法
-(NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) return _managedObjectModel;
//.xcdatamodeld文件 编译之后变成.momd文件 (.mom文件)
NSURL * modelURL = [[NSBundle mainBundle] URLForResource:coreDataModelName withExtension:@"momd"];
//把文件的内容读取到managedObjectModel中
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
//Coordinator 调度者负责数据库的操作 创建数据库 打开数据 增删改查数据
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) return _persistentStoreCoordinator;
//根据model创建了persistentStoreCoordinator
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
// 设置数据库存放的路径
NSURL * storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:sqliteName];
NSError * error = nil;
//如果没有得到数据库,程序崩溃
/*
持久化存储库的类型:
NSSQLiteStoreType SQLite数据库
NSBinaryStoreType 二进制平面文件
NSInMemoryStoreType 内存库,无法永久保存数据
虽然这3种类型的性能从速度上来说都差不多,但从数据模型中保留下来的信息却不一样
在几乎所有的情景中,都应该采用默认设置,使用SQLite作为持久化存储库
*/
// 添加一个持久化存储库并设置类型和路径,NSSQLiteStoreType:SQLite作为存储库
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
if (error) {
NSLog(@"添加数据库失败:%@",error);
} else {
NSLog(@"添加数据库成功");
}
NSLog(@"错误信息: %@, %@", error, [error userInfo]);
}
return _persistentStoreCoordinator;
}
-(NSURL *)applicationDocumentsDirectory
{
//获取沙盒路径下documents文件夹的路径 NSURL (类似于search)
NSLog(@"%@",[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject].absoluteString);
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
//容器类 存放OC的对象
-(NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) return _managedObjectContext;
NSPersistentStoreCoordinator * coordinator = [self persistentStoreCoordinator];
if (!coordinator)
{
return nil;
}
//创建context对象
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
//让context和coordinator关联 context可以对数据进行增删改查功能 // 设置上下文所要关联的持久化存储库
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
@end
6、具体使用
-
增 insert
NSDictionary * dict = @{@"title":@"title2",@"content":@"content2"}; [[CoreDataManager sharedInstance] insertNewEntity:dict success:^{ NSLog(@"成功"); } fail:^(NSError *error) { NSLog(@"失败"); }];
运行结果 :
2018-11-12 13:25:06.730756+0800 CoreDataText[1600:1182994] 添加数据成功
数据库中显示:
-
查询 select
[[CoreDataManager sharedInstance] selectEntity:nil ascending:YES filterString:nil success:^(NSArray *results) { NSLog(@"数据---%@",results); } fail:^(NSError *error) { }];
运行结果:
-
改 updata
[[CoreDataManager sharedInstance] selectEntity:nil ascending:YES filterString:nil success:^(NSArray *results) { NSLog(@"数据---%@",results); if (results.count>0) { //更新某个 NSManagedObject * model = [results firstObject]; [model setValue:@"xiugaile title" forKey:@"title"]; [model setValue:@"xiugaile content" forKey:@"content"]; [[CoreDataManager sharedInstance] updateEntity:^{ } fail:^(NSError *error) { }]; } } fail:^(NSError *error) { }];
运行结果 :
-
删除 delete
//删除某个 NSString * filterString = [NSString stringWithFormat:@"title = 'title'"]; [[CoreDataManager sharedInstance] selectEntity:nil ascending:YES filterString:filterString success:^(NSArray *results) { NSLog(@"数据---%@",results); if (results.count>0) { //删除某个 [[CoreDataManager sharedInstance] deleteEntity:[results firstObject] success:^{ } fail:^(NSError *error) { }]; } } fail:^(NSError *error) { }]; //全部删除 [[CoreDataManager sharedInstance] selectEntity:nil ascending:YES filterString:nil success:^(NSArray *results) { NSLog(@"数据---%@",results); //全部删除 for (NSManagedObject *obj in results){ [[CoreDataManager sharedInstance] deleteEntity:obj success:^{ } fail:^(NSError *error) { }]; } } fail:^(NSError *error) { }];
运行结果:
参考:
https://blog.csdn.net/u013983033/article/details/83378838
https://www.jianshu.com/p/e98daf9fec78
https://www.jianshu.com/p/332cba029b95
https://www.jianshu.com/p/e676ade9fcc6
https://www.jianshu.com/p/c640dc6fd0e0