咱们不扯那么多,直接开始,
先简单介绍下CoreData吧,CoreData是苹果公司封装的进行数据持久化的框架,首次在iOS3.0版本的系统中出现,它允许按照实体-属性-值模型组织数据,并以xml,二进制文件或者SQLite数据文件的格式持久化数据。
看完上面的定义我们要知道,1,CoreData并不是数据库,他只是苹果封装的一个框架,通过这个框架我们很方便的可以进行数据持久化,2,他不仅支持SQLite还支持xml,二进制文件,还可以自定义自己的储存类型 3,支持可视化建模(我们等会通过demo来了解为什么支持可视化建模)4,CoreData支持模型版本升级(后面会讲到怎么升级),概念就说到这吧,我也是在网上看的,你还想了解更多,自己查一下。
下面我们看一下CoreData原理,先上个让我们看见就迷糊的图吧
是不是一头雾水,,这些都是CoreData需要的一些类,下面咱们通过工程来理解一下
1,首先先建个空工程,如图,到这一步要勾选User Core Data,勾选的好处是,工程会给我们自动生成一些代码,如果不勾选,那些代码还要自己去写,具体什么代码,工程建完之后你会看到
2,我们看一下工程,如图,红色圈着的文件就是我们上面提到的支持可视化建模,我们创建模型就在这里面创建,下面会讲怎么创建,我们接着看AppDelegate里面多出来的代码,是干什么用的
3,我们Appdelegate.h是不是多出来这些代码
@property (readonly,strong, nonatomic)NSManagedObjectContext *managedObjectContext;
@property (readonly,strong, nonatomic)NSManagedObjectModel *managedObjectModel;
@property (readonly,strong, nonatomic)NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
NSManagedObjectContext管理对象上下文的类(数据管理器),相当于一个临时数据库,就是我们上边看到CoreData层级图里面最上层的部分,我们操作数据都是通过这个类,我们不能直接访问源数据的,就像svn一样,我们只有在我们本地工作目录里面修改,再同步到服务器。有人会问,为什么第一层会有那么多不同的类呢,因为Coredata框架中多线程的处理,在不同的线层中用不同的类,具体在什么线程,用什么类,这个我们不用操心,框架里面已经为我们处理好了。
NSManagedObjectModel被管理对象模型(数据模型器),就是上边CoreData层级图中最右边的那部分,我们可以把他看成我们工程里面.cdatamodeld这个文件,这个文件我们还没有创建实体,所以还不能创建模型,如图红色圈着的那部分还不能点击,等下我们创建完实体,就能创建模型了,模型就是我们平常将创建的model
NSPersistentStoreCoordinator持久化储存助理(数据连接器)整个CoreData框架中的核心,就是上边CoreData层级图中间绿色的那部分,它就是将我们在NSManagedObjectContext类中操作的数据和源数据就行链接的功能,没有他我们无论怎么操作NSManagedObjectContext来修改数据,源数据都不会变的。
- (void)saveContext;这个方法就是把我们临时数据进行永久保留,我们通过NSManagedObjectContext操作完数据之后要调用这个方法把他保存到本地,才能实现永久保存
- (NSURL *)applicationDocumentsDirectory;获得真实文件的储存路径(真实的文件就是我们上图CoreData层级图最下面的几个长得像圆筒那部分,他们就是本地数据库)
下面我们来创建个实体如下图,点击下图Add Entity增加一个实体Entity,我们可以双击Entity给他改个名字叫Car
然后我们点击Attributes为实体Car添加两个属性一个name String型的,一个price Int型的,如图
创建玩实体我们再看创建model那一项已经变成可点击了,这时候我们就可以创建model了,如图点击红色圈着的部分,一直往下点next
到这一步(如下图)要勾选上Car,因为我们可能可视化建模里面创建好几个实体,这时候你就要选择为哪个实体创建model
好这时候你会看到四个文件,Car.h Car.m Car+CoreDataProperties.h Car+CoreDataProperties.m,在Car+CoreDataProperties.h我们会看到系统自动为我们生成了Car的属性name和price,好现在model有了,到时候我们引入model的时候引入Car.h就行了,我们开始写代码了。
我们先点开Main.storyboard把ui给弄一下,首先给viewController添加一个导航栏,如下图,选中Main.storyboard,点击Editor-Embed In - Navigation Controller,就为view Controller添加上了导航栏
有了导航栏我们为导航栏拖拽一个Bar Button item,把他的System Item 设置为Add,样式如下图,我截个小点的图吧,我们为这个Bar Button Item拖拽一个点击事件叫addModel,怎么拖的我就不截图了,图太多了
下一步我们添加一个Tableview,然后为他增加个Cell,把Prototype设置为1就行了,如下图
然后我们选中cell,把cell的Identifier写上cell,你可以写其他字符串,这只是个标示,你在这些什么,你工程代码写什么就行了,把Style设置为Basic,设置完之后,别忘了把你的tableView的dataSource和delegate和你的viewController关联一下,然后把你的tableView拖拽个属性,我的叫dataTb,完了之后我们打开viewController开始写代码了
我们先把需要用到tableView的delegate和dataSource方法写上,需要用到的有:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section//返回row的个数
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath//创建cell
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath//是否可编辑
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath//编辑类型我们要在里面轻滑删除数据用的
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath//选中的时候我们改变数据
这些方法你先加上,等下写什么代码,会给大家的
下面我们开始往CoreData里面添加数据,并且显示到我们的tabelView上
我们找到
- (IBAction)addModel:(id)sender这个方法,就是我们刚才通过bar button item关联的方法,在里面写代码之前我们要建一个全局可变数组和AppDelegate对象,我创建的如下
self.dataArr = [NSMutableArrayarray];
self.appDelgate = [UIApplicationsharedApplication].delegate;
然后我们把我们的Car头文件引入到viewController里面
这时候就可以开始写了,代码如下
- (IBAction)addModel:(id)sender {
/*
创建实体描述对象,因为在可视化建模文件里面我们可能创建好多实体,这时候我们就要用实体描述,来描述为哪个实体创建模型对象,这时候我们为实体Car创建模型对象,所以entityForName要传Car,不要写错了啊
*/
NSEntityDescription *descriotion = [NSEntityDescriptionentityForName:@"Car"inManagedObjectContext:self.appDelgate.managedObjectContext];
//创建一个模型对象,这里面需要两个参数一个是实体描述对象,一个是我们上下文文本
Car *car = [[Caralloc] initWithEntity:descriotioninsertIntoManagedObjectContext:self.appDelgate.managedObjectContext];
/*
添加数据
*/
car.name =@"BMW";
int price = arc4random()%100000 +1000; //价格为随机数
car.price = [NSNumbernumberWithInt:price];
[self.dataArraddObject:car];//放到数组用来显示
//插入ui,我们为他添加了一个从左向右的动画UITableViewRowAnimationLeft
[self.dataTbinsertRowsAtIndexPaths:@[[NSIndexPathindexPathForRow:self.dataArr.count-1inSection:0]]withRowAnimation:UITableViewRowAnimationLeft];
//我们只有调用saveContext才能把数据存到我们本地仓库里面,才能实现本地化永久储存
[self.appDelgatesaveContext];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.dataArr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCellalloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:@"cell"];
Car *car = self.dataArr[indexPath.row];
cell.textLabel.text = [NSStringstringWithFormat:@"%@_____%@",car.name,car.price];
return cell;
}
当我们才再次运行,没有数据,因为我们启动没有把本地数据查询出来,下面我们在- (void)viewDidLoad里面添加查询代码,代码如下
- (void)viewDidLoad {
[superviewDidLoad];
//初始化数组
self.dataArr = [NSMutableArrayarray];
self.appDelgate = [UIApplicationsharedApplication].delegate;
//查询数据,initWithEntityName参数要填你要查询的实体,我们知道可视化建模里面有好多实体,所以你查什么,就要填什么,不要写错哦
NSFetchRequest *request = [[NSFetchRequestalloc] initWithEntityName:@"Car"];
//我们还可以为查询添加查询条件,我们通过价格price来排序,price不要写错了哦,ascending设为yes,说明我们是按生序排序
NSSortDescriptor *sortDescriptor = [[NSSortDescriptoralloc] initWithKey:@"price"ascending:YES];
//这是个数组类型的,说明我们可以有多个排序准则
request.sortDescriptors =@[sortDescriptor];
//执行查询请求,这时候我们用managedObjectContext来操作,因为我们前面讲到我们对数据操作都是通过这个类
NSError *error = nil;
NSArray *result = [self.appDelgate.managedObjectContextexecuteFetchRequest:request error:&error];
[self.dataArraddObjectsFromArray:result];
}
//设置为可编辑
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
//tableView编辑方法
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle ==UITableViewCellEditingStyleDelete) {
//删除数据
Car *car = self.dataArr[indexPath.row];
[self.dataArrremoveObject:car];
//删除数据管理器中的数据,还是通过NSManagedObjectContext来操作的
[self.appDelgate.managedObjectContextdeleteObject:car];
//进行永久保存
[self.appDelgatesaveContext];
//删除单元格
[self.dataTbdeleteRowsAtIndexPaths:@[indexPath]withRowAnimation:UITableViewRowAnimationFade];
}
}
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath这个方法,我们通过点击cell来修改数据
/*
点击cell的方法用来修改数据
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//先找到模型对象
Car *car = self.dataArr[indexPath.row];
car.name =@"大众";
//刷新单元格
[self.dataTbreloadRowsAtIndexPaths:@[indexPath]withRowAnimation:UITableViewRowAnimationAutomatic];
//通过saveContext方法对数据进行永久保存
[self.appDelgatesaveContext];
}
写完上面的代码,我们可以运行试一下,点击cell看数据有没有改变,如果成功了,那么CoreData的增删改查,就完了,如果想看CoreData怎么升级,接着往下面看
CoreData升级
如果我们想在CoreDataDemo.xcdatamodeld这个文件,为我们刚才创建Car实体添加一个属性,这时候我们不能直接点击下面的加号(红色圈着的部分)来添加,如果点击下面的加号直接添加会崩溃,如下图这时候我们就涉及到CoreData版本迁徙,版本升级
具体怎么做,看下面的步骤,找到红色圈着的部分,这时候我们创建了一个CoreDataDemo2.xcdatamodeld
这时候我们看到,选中的还是老版本,绿色对号选中个那个文件,我们怎么让它选中我们新建的可视化建模文件呢,选中可视化建模总集合,也就是最上面那个文件
选中之后我们找到右边第一个标签,如图,我们找到红色圈着部分,选择我们刚才新创建的CoreDataDemo2,这时候绿色对号就跑到CoreDataDemo2.xcdatamodeld上面了,这时候我们就可以在这个新的模型版本添加属性了,我添加个type试试,类型为string,千万不要在老的模型版本里面添加,添加完之后接着往下面看
下面我们还要创建映射关系,如下图,我创建到info.plist文件下面吧,点command+n我们找到ios下面的Core Data选中红色圈着部分,映射模型,然后下一步
到这一步会让我选中版本可视化建模文件,我们选中老版本可视化建模文件(红色圈着部分),然后点击下一步)
这一步让我们选择新的可视化建模文件,大家知道选哪个吧,我就不截图了,保存的时候让取个名字,我取的是v0_v1,大家随便取,这时候我们映射文件就创建好了,这时候我们到AppDelegate.m文件改下代码
我们找到- (NSPersistentStoreCoordinator *)persistentStoreCoordinator这个方法,找到
if (![_persistentStoreCoordinatoraddPersistentStoreWithType:NSSQLiteStoreTypeconfiguration:nilURL:storeURL options:nilerror:&error]) {
}
if (![_persistentStoreCoordinatoraddPersistentStoreWithType:NSSQLiteStoreTypeconfiguration:nilURL:storeURLoptions:@{NSMigratePersistentStoresAutomaticallyOption :@YES} error:&error]) {
}