数据存储之CoreData(基础)
ios开发常用的五种数据存储方式:
- plist
- NSUserDefaults
- NSKeyedArchiver
- FMDB
- CoreData
这篇文章我们主要回顾Core Data的使用
Core Data
因为Core data涉及到的东西较多,在这里先写一些入门的操作(多表关联以后会更新)
core data涉及到的一些类:
(1)NSManagedObjectContext(被管理的数据上下文)
操作实际内容(操作持久层)
作用:插入数据,查询数据,删除数据
(2)NSManagedObjectModel(被管理的数据模型)
数据库所有表格或数据结构,包含各实体的定义信息
作用:添加实体的属性,建立属性之间的关系
操作方法:视图编辑器,或代码
(3)NSPersistentStoreCoordinator(持久化存储助理)
相当于数据库的连接器
作用:设置数据存储的名字,位置,存储方式,和存储时机
(4)NSManagedObject(被管理的数据记录)
相当于数据库中的表格记录
(5)NSFetchRequest(获取数据的请求)
相当于查询语句
(6)NSEntityDescription(实体结构)
相当于表格结构,NSEntityDescription对象包含了Entity所拥有的属性,关系等信息,我们可以通过NSEntityDescription生成相应的NSManagedObject的实体
coredata的使用
1.创建coreDataDemo 如图选中User Core Data
90FF46FE-6465-49C2-9FD7-3CDAA95D6855.png
“Use Core Data”这个勾给我们做了些额外的工作,一是将“CoreData.framework”增加到我们工程的Frameworks列表中来了,二是在AppDelegate中增加了一些关于CoreData的代码.
如果你的工程没勾选“Use Core Data”这个选项,你也可以模仿一个新创建的“Use Core Data”的工程把必要的代码添加上去,完全没问题.
选中
屏幕快照 2016-11-29 下午8.57.28.png
2.添加实体
53464188-A7E9-46C4-B46D-2FBF96C0C8B9.png
3.然后新建一个file,记得是NSManagedObject cubclass
5556A2E1-D835-4007-AC99-72A6CD50DF3F.png
0E3675FA-EC3C-47A5-8391-9B9C5E01D3D9.png
BA7400A0-AEFB-4114-9726-FC643F3121B1.png
生成四个文件(ios7之前是两个)
屏幕快照 2016-11-30 下午12.40.07.png
4.代码示例
下面我们建立一个单例来演示coredate的 增、删、改、查功能
(1) 增
//增
-(BOOL)saveCarInfoByCarModel:(CarModel *)carmodel
{
BOOL retVal = NO;
//NSManagedObjectContext(被管理的数据上下文),操作实际内容(操作持久层)作用:插入数据,查询数据,删除数据
NSManagedObjectContext *context = [APPDELEGATE managedObjectContext];
//下面代码相当于 alloc init 初始化
Car *car = [NSEntityDescription insertNewObjectForEntityForName:@"Car" inManagedObjectContext:context];
car.userID = carmodel.userID;
car.carID = carmodel.carID;
car.carName = carmodel.carName;
car.carNumber = carmodel.carNumber;
car.carIsDefault = carmodel.carIdDefault;
NSError *error;
if ([context save:&error]) {
NSLog(@"保存成功");
retVal = YES;
}
return retVal;
}
在VC中执行
-(void)insertAction
{
CarModel *carmodel = [[CarModel alloc]init];
carmodel.userID = @"2011";
carmodel.carID = @"1dwdwq";
carmodel.carName = @"兰博基尼";
carmodel.carNumber = @"京A93459";
carmodel.carIdDefault = @"0";
if ([[SingleTon sharedSingleTon] saveCarInfoByCarModel:carmodel]) {
NSLog(@"插入数据成功");
}
}
在此之前我们需要在appdelegate中打印数据库的地址便于查看数据信息
F65A0799-062D-4FBF-80A1-3835F27AA2C1.png
运行结果如下:
2016-11-30 12:51:29.163 coreDataDemo[31612:1990693] file:///Users/x8f/Library/Developer/CoreSimulator/Devices/7A1AE587-2880-40CE-A11B-17F7DFE94ACD/data/Containers/Data/Application/D66488E1-0E5E-44F8-B75A-5C44DD5954CF/Documents/coreDataDemo.sqlite
2016-11-30 12:51:29.174 coreDataDemo[31612:1990693] 保存成功
2016-11-30 12:51:29.174 coreDataDemo[31612:1990693] 插入数据成功
前往-->前往文件夹-->输入数据库地址后看到:
屏幕快照 2016-11-30 下午12.53.26.png
使用SQLiteManager打开数据库文件
数据库下载地址:https://github.com/skyxian/SQLiteManager
屏幕快照 2016-11-30 下午12.53.50.png
屏幕快照 2016-11-30 下午12.54.12.png
数据添加成功 !
然后我们再多添加几个数据便于改、删、查的操作演示
我添加了六条数据如下:
1.02.33.png
(2) 删
//删:根据carID来删除carID对应的那个车辆
-(BOOL)deleteCarInfoByCarID:(NSString *)carID
{
BOOL retVal = NO;
NSManagedObjectContext *context = [APPDELEGATE managedObjectContext];
//建立请求
NSFetchRequest *request = [[NSFetchRequest alloc]init];
//读取所有Car
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Car" inManagedObjectContext:context];
request.entity = entity;
//设置检索条件(不设则默认检索所有Car)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"carID=%@",carID];
request.predicate = predicate;
NSError *error;
NSArray *arr = [context executeFetchRequest:request error:&error];
if (arr.count) {
for (Car *car in arr) {
//删除对象
[context deleteObject:car];
}
//保存删除的结果
if ([context save:nil]) {
retVal = YES;
}
}else{
NSLog(@"没有检索到对象");
}
return retVal;
}
VC中我们执行 删除carID = @"e28r22"的那个car对象的操作
-(void)deleteAction
{
CarModel *carmodel = [[CarModel alloc]init];
carmodel.carID = @"e28r22";
if ([[SingleTon sharedSingleTon] deleteCarInfoByCarID:carmodel.carID]) {
NSLog(@"删除数据成功");
}
}
打印结果如下:
2016-11-30 13:15:33.410 coreDataDemo[31862:2004730] file:///Users/x8f/Library/Developer/CoreSimulator/Devices/7A1AE587-2880-40CE-A11B-17F7DFE94ACD/data/Containers/Data/Application/6A977C79-3A51-449D-8D5E-EF5F8009D2EA/Documents/coreDataDemo.sqlite
2016-11-30 13:15:33.417 coreDataDemo[31862:2004730] 删除数据成功
我们打开数据库查看
1.18.15.png
carID为@"e28r22"的那个car对象被我们成功删除!
(3) 改
由上图我们看到数据库还有5条数据,现在我们修改userid为2012 carid为r3nkr3 的数据信息(coredata中使用&&连接符)
//改:根据userID以及carID来修改车辆信息
-(BOOL)updateCarInfoByCarModel:(CarModel *)carmodel
{
BOOL retVal = NO;
NSManagedObjectContext *context = [APPDELEGATE managedObjectContext];
//建立请求
NSFetchRequest *request = [[NSFetchRequest alloc]init];
//读取所有Car
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Car" inManagedObjectContext:context];
request.entity = entity;
//设置检索条件(不设则默认检索所有Car)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"userID = %@ && carID = %@",carmodel.userID,carmodel.carID];
request.predicate = predicate;
NSError *error;
NSArray *arr = [context executeFetchRequest:request error:&error];
if (arr.count) {
for (Car *car in arr) {
car.userID = carmodel.userID;
car.carID = carmodel.carID;
car.carIsDefault = carmodel.carIdDefault;
car.carName = carmodel.carName;
car.carNumber = carmodel.carNumber;
if ([context save:nil]) {
retVal = YES;
}
}
}else{
NSLog(@"没有检索到对象");
}
return retVal;
}
在VC中执行
-(void)updateAction
{
CarModel *carmodel = [[CarModel alloc]init];
carmodel.userID = @"2012";
carmodel.carID = @"r3nkr3";
carmodel.carName = @"路虎";
carmodel.carNumber = @"京A80808";
carmodel.carIdDefault = @"1";
if ([[SingleTon sharedSingleTon] updateCarInfoByCarModel:carmodel]) {
NSLog(@"更新数据成功");
}
}
去数据库查看
BCB302D6-83F6-4410-9DAC-5DA5EA91D8A1.png
userid为2012 carid为r3nkr3 的数据被成功修改
(4) 查
我们来查找所有userid为2010的车辆信息
// 查:根据userID查寻该userID对应的所有车辆
-(NSArray *)queryCarInfoByUserID:(NSString *)userID
{
NSManagedObjectContext *context = [APPDELEGATE managedObjectContext];
//建立请求
NSFetchRequest *request = [[NSFetchRequest alloc]init];
//读取所有Car
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Car" inManagedObjectContext:context];
request.entity = entity;
//设置检索条件(不设则默认检索所有Car)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"userID = %@",userID];
request.predicate = predicate;
NSError *error;
NSMutableArray *listArr = [NSMutableArray new];
NSArray *arr = [context executeFetchRequest:request error:&error];
for (Car *car in arr) {
CarModel *model = [[CarModel alloc]init];
model.userID = car.userID;
model.carID = car.carID;
model.carIdDefault = car.carIsDefault;
model.carName = car.carName;
model.carNumber = car.carNumber;
[listArr addObject:model];
}
return listArr;
}
VC中执行
-(void)queryAction
{
CarModel *carmodel = [[CarModel alloc]init];
carmodel.userID = @"2010";
NSArray *arr = [[SingleTon sharedSingleTon]queryCarInfoByUserID:carmodel.userID];
if (arr) {
for (CarModel *model in arr) {
NSLog(@"%@---%@---%@---%@---%@",model.userID,model.carID,model.carName,model.carNumber,model.carIdDefault);
}
}
}
打印结果如下
2016-11-30 13:35:24.914 coreDataDemo[31986:2016010] file:///Users/x8f/Library/Developer/CoreSimulator/Devices/7A1AE587-2880-40CE-A11B-17F7DFE94ACD/data/Containers/Data/Application/99FCBB9B-41BD-460F-BF23-7231126FDFC4/Documents/coreDataDemo.sqlite
2016-11-30 13:35:24.919 coreDataDemo[31986:2016010] 2010---29eh4f---法拉利---京A429e8---1
2016-11-30 13:35:24.919 coreDataDemo[31986:2016010] 2010---bi3k1---大众---京A82eb2---0
2016-11-30 13:35:24.919 coreDataDemo[31986:2016010] 2010---9d20d2---蒙迪欧---京A11111---0
查询成功 !
数据迁移
假设存在这样一个场景,car这个实体现有的属性字段已经无法满足我们的需求,需要给它添加几个字段并修改原有的部分字段,这个时候我们就需要使用数据迁移了,否则程序会crash!
ok !我们在本demo中继续演示 版本迁移
(1) 选中你的coreDataDemo.xcdatamodeld文件,选择Xcode菜单editor->Add Model Version
比如取名:coreDataDemo 2.xcdatamodel
屏幕快照 2016-11-30 下午2.25.21.png
1628981F-4EEC-4084-BBCE-56FEC8D70CE9.png
这个时候你会发现CoreData.xcdatamodeld中多了一个版本文件,如图:
屏幕快照 2016-11-30 下午2.39.05.png
(2) 选择刚才创建的版本,在inspector中的Versioned Core Data Model选择Current模版为coreDataDemo 2.xcdatamodel
451AC5F8-650F-4D14-9971-8B88CE127F9D.png
(3) 修改新数据模型coreDataDemo 2,在新的文件上添加属性字段和修改实体 ( 切记!!!是在新的coreDataDemo 2上添加及修改属性)
9326245E-F836-4E78-AAEB-5C1376ABBFBC.png
(4) 修改原来的实体文件(或者删除原来的实体文件,重新生成新的实体下的类)
C38126DA-403D-4EC3-A6C1-F3F69D00DE20.png
1CF7413C-187E-431B-BC84-AD22EFC67730.png
(5)在AppDelegate.m的persistentStoreCoordinator中添加代码:
758E84FB-E3E8-4DBC-A74C-EFB22D63EFC9.png
运行--成功 !
现在我们再次向数据库中添加一条数据看看有什么效果
-(void)insertAction
{
/*
*
* 这里最好多添加几条数据便于后面 删、改、查 的操作演示
*
*/
CarModel *carmodel = [[CarModel alloc]init];
carmodel.userID = @"2013";
carmodel.carID = @"8f3hf3";
carmodel.carName = @"法拉利";
carmodel.carNumber = @"京A86868";
carmodel.carIdDefault = @"0";
if ([[SingleTon sharedSingleTon] saveCarInfoByCarModel:carmodel]) {
NSLog(@"插入数据成功");
}
}
打印结果:
2016-11-30 15:02:35.063 coreDataDemo[32513:2055137] file:///Users/x8f/Library/Developer/CoreSimulator/Devices/7A1AE587-2880-40CE-A11B-17F7DFE94ACD/data/Containers/Data/Application/EF713FA9-E1D0-4E42-BC6A-CBBF438AB4A9/Documents/coreDataDemo.sqlite
2016-11-30 15:02:35.136 coreDataDemo[32513:2055137] 保存成功
2016-11-30 15:02:35.136 coreDataDemo[32513:2055137] 插入数据成功
进入数据库查看
05AA1904-6652-4518-8DB1-32DE310443CD.png
数据添加成功,且数据库中多了一个carDistance的字段,说明数据迁移成功!