CoreData
CoreData中几乎不用写数据库操作语句就能完成数据的本地化存储。
CoreData和iOS中的模型对象相联系在一起,只需要操作模型对象的增删改查就可以完成数据的增删改查,不用写SQL语句。
CoreData的存储方式
SQLite NSSQLiteStoreType
XML NSXMLStoreType
Binary NSBinaryStoreType
内存存储 NSInMemoryStoreType
CoreData的核心对象
NSManagedObjectContext 用途:负责应用与数据库之间的交互
NSPersistentStoreCoordinator 用途:添加持久化数据库,如SQLite
NSManagedObjectModel 用途:代表CoreData的模型文件
NSEntityDescription 用途:用于描述实体
CoreData的使用步骤
创建模型文件【相当于创建数据库】
添加实体【相当于创建表】
创建实体类【相当于创建模型】
生成上下文文件,关联模型文件生成数据库
保存对象到数据库
从数据库获取对象
更新数据
删除数据
创建上下文
配置好后,创建文件:
创建完成。
接着配置一下工程项目配置:
然后在需要用到数据库的地方importCoreData框架,才可以使用CoreData相关的API。
这个时候如果编译上有遇到重复编译相关文件的错误提示的话,那就去这个地方将相关的提示文件删除即可。
然后再需要调用的地方生成上下文,上下文是用来关联数据文件(CoreData__1.xcdatamodeld)的。
- (void)initCoreDataContext{
//生成上下文,关联数据文件
NSManagedObjectContext* context = [[NSManagedObjectContext alloc]init];
//创建模型对象:mergedModelFromBundles:nil传入nil,会将bundle下所有的模型文件都关联起来
NSManagedObjectModel* model = [NSManagedObjectModel mergedModelFromBundles:nil];
//创建持久化调度器:
NSPersistentStoreCoordinator* store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
//获取存储数据库的名字
//创建获取error的变量,用于接收错误
NSError* error = nil;
//创建数据库的存储路径:
NSString* doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString* sqlitePath = [doc stringByAppendingPathComponent:@"CoreData__1.sqlite"];
NSURL* sqlURL = [NSURL fileURLWithPath:sqlitePath];
NSLog(@"数据库位置:%@",sqlitePath);
[store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sqlURL options:nil error:&error];
context.persistentStoreCoordinator = store;
self.context = context;
}
运行查看下文件路径有没有创建数据库文件:
2022-03-04 14:44:09.148267+0800 CoreData实践1[70691:2979529] 数据库位置:/Users/housnk/Library/Developer/CoreSimulator/Devices/1BD9D98C-0C2C-4F1A-8ADD-9158B1C4C938/data/Containers/Data/Application/6DBDFD9C-0D7E-449C-8B92-669DC0C0133F/Documents/CoreData__1.sqlite
用文件夹前往文件所在的位置:
文件已生成没错。
添加数据
接着我们再创建一个方法用于添加数据:
PS:记得导入模型头文件。
#import "CoreData/Person+CoreDataProperties.h"
- (void)addInfo:(NSString*)name age:(int64_t)age{
//用上下文来创建一个模型对象
Person* person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.context];
//给该模型对象赋值
int numberID = arc4random()%10000;
person.name = [NSString stringWithFormat:@"personSomeone%d",numberID];
//旧版本的CoreData会将基本数据类型如Int、Float等包装成NSNumber对象,这里是新版本不用。
int64_t personAge = arc4random()%100;
person.age = personAge;
//通过上下文保存:
//创建一个error用于接收错误,如果有错误的话。
NSError* error = nil;
[self.context save:&error];
if (error) {
NSLog(@"保存失败,错误信息:%@",error);
}else{
NSLog(@"保存成功");
}
}
然后再运行一下,同样需要重新进入一下文件路径,因为每次编译后,其文件路径都有可能会改变。
运行结果:
2022-03-04 14:50:37.138301+0800 CoreData实践1[70833:2986457] 数据库位置:/Users/housnk/Library/Developer/CoreSimulator/Devices/1BD9D98C-0C2C-4F1A-8ADD-9158B1C4C938/data/Containers/Data/Application/6D76C9FC-93AA-4BC9-B443-C052171674E7/Documents/CoreData__1.sqlite
2022-03-04 14:50:37.185076+0800 CoreData实践1[70833:2986457] 保存成功
可以看到保存成功,有数据库查看软件的朋友可以进入到上面数据库存放的路径进行查阅。
没有数据库查看软件的朋友可以使用终端进行查看。这里使用终端进行查看软件。
打开终端,进入到数据库文件路径,如下:
关于终端如何操作数据库可以点阅这篇文章:终端下简单查看SQLite数据库
查阅数据
- (void)readData{
//创建请求对象(填入的是表名称)
NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
//读取信息,几乎所有的增删改查都是使用context上下文进行操作
//创建一个error用于接收错误,如果有错误的话。
NSError* error = nil;
//创建一个数组用于接收查询到的数据对象
NSArray* resultArray = [self.context executeFetchRequest:request error:&error];
if (error) {
NSLog(@"查询失败,错误信息:%@",error);
}else{
NSLog(@"查询结果如下%@",resultArray);
}
}
运行结果;
2022-03-04 15:36:29.121111+0800 CoreData实践1[71748:3018667] 查询结果如下(
"<Person: 0x60000010f020> (entity: Person; id: 0x913f42003aea29b9 <x-coredata://87F63B23-49E7-4631-B8A1-3305DFF756A4/Person/p1>; data: <fault>)"
)
由结果可得,其数组里面是Person对象,可以直接取出来用的。
过滤查询
接下来,我们用添加数据单元的方法,增加多几条数据,这个过程就不赘述了,主要是作为用于实践过滤查询的数据源,增加样本。
调用方式:
//读取数据
[self readAllData];
//筛查
[self filtrateData];
筛查部分执行代码:
- (void)filtrateData{
//创建请求对象(填入的是表名称)
NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
//创建过滤器
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"age<50"];
request.predicate = predicate;
//读取信息,几乎所有的增删改查都是使用context上下文进行操作
//创建一个error用于接收错误,如果有错误的话。
NSError* error = nil;
//创建一个数组用于接收查询到的数据对象
NSArray* resultArray = [self.context executeFetchRequest:request error:&error];
if (error) {
NSLog(@"查询失败,错误信息:%@",error);
}else{
NSLog(@"查询结果如下");
for (Person* person in resultArray) {
NSLog(@"personName:%@ age:%zd",person.name,person.age);
}
}
}
运行结果:
2022-03-04 15:52:48.250085+0800 CoreData实践1[72074:3032433] 查询结果如下
2022-03-04 15:52:48.250414+0800 CoreData实践1[72074:3032433] personName:personSomeone8011 age:92
2022-03-04 15:52:48.250558+0800 CoreData实践1[72074:3032433] personName:personSomeone5165 age:31
2022-03-04 15:52:48.250731+0800 CoreData实践1[72074:3032433] personName:personSomeone4661 age:1
2022-03-04 15:52:48.250833+0800 CoreData实践1[72074:3032433] personName:personSomeone5009 age:0
2022-03-04 15:52:48.250962+0800 CoreData实践1[72074:3032433] personName:personSomeone5947 age:85
2022-03-04 15:52:48.251089+0800 CoreData实践1[72074:3032433] personName:personSomeone7893 age:71
2022-03-04 15:52:48.251191+0800 CoreData实践1[72074:3032433] personName:personSomeone5098 age:40
2022-03-04 15:52:48.251342+0800 CoreData实践1[72074:3032433] personName:personSomeone4730 age:26
2022-03-04 15:52:48.251525+0800 CoreData实践1[72074:3032433] personName:personSomeone5643 age:61
2022-03-04 15:52:48.251730+0800 CoreData实践1[72074:3032433] personName:personSomeone2079 age:26
2022-03-04 15:52:48.252403+0800 CoreData实践1[72074:3032433] 查询结果如下
2022-03-04 15:52:48.253705+0800 CoreData实践1[72074:3032433] personName:personSomeone5165 age:31
2022-03-04 15:52:48.253820+0800 CoreData实践1[72074:3032433] personName:personSomeone4661 age:1
2022-03-04 15:52:48.253905+0800 CoreData实践1[72074:3032433] personName:personSomeone5009 age:0
2022-03-04 15:52:48.254002+0800 CoreData实践1[72074:3032433] personName:personSomeone5098 age:40
2022-03-04 15:52:48.254094+0800 CoreData实践1[72074:3032433] personName:personSomeone4730 age:26
2022-03-04 15:52:48.254196+0800 CoreData实践1[72074:3032433] personName:personSomeone2079 age:26
可以看到数据的确把age<50的给筛选出来了。
复杂的过滤查询
就是增加一些字符而已:
比如我要查询年纪大于18小于65的适龄劳动人员,那么就可以这么写:
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"age<65 AND age>18"];
运行结果:
2022-03-04 15:58:28.557047+0800 CoreData实践1[72165:3037445] 查询结果如下
2022-03-04 15:58:28.557156+0800 CoreData实践1[72165:3037445] personName:personSomeone5165 age:31
2022-03-04 15:58:28.640364+0800 CoreData实践1[72165:3037445] personName:personSomeone5098 age:40
2022-03-04 15:58:28.640592+0800 CoreData实践1[72165:3037445] personName:personSomeone4730 age:26
2022-03-04 15:58:28.640689+0800 CoreData实践1[72165:3037445] personName:personSomeone5643 age:61
2022-03-04 15:58:28.640776+0800 CoreData实践1[72165:3037445] personName:personSomeone2079 age:26
对结果排序
- (void)filtrateAndSortData{
//创建请求对象(填入的是表名称)
NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
//创建过滤器
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"age<65 AND age>18"];
request.predicate = predicate;
//读取信息,几乎所有的增删改查都是使用context上下文进行操作
//以年纪进行排序
NSSortDescriptor* sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:YES];
request.sortDescriptors = @[sort];
//创建一个error用于接收错误,如果有错误的话。
NSError* error = nil;
//创建一个数组用于接收查询到的数据对象
NSArray* resultArray = [self.context executeFetchRequest:request error:&error];
if (error) {
NSLog(@"查询失败,错误信息:%@",error);
}else{
NSLog(@"查询结果如下");
for (Person* person in resultArray) {
NSLog(@"personName:%@ age:%zd",person.name,person.age);
}
}
}
运行结果:
2022-03-04 16:09:23.233057+0800 CoreData实践1[72352:3044306] 查询结果如下
2022-03-04 16:09:23.233216+0800 CoreData实践1[72352:3044306] personName:personSomeone4730 age:26
2022-03-04 16:09:23.233541+0800 CoreData实践1[72352:3044306] personName:personSomeone2079 age:26
2022-03-04 16:09:23.233638+0800 CoreData实践1[72352:3044306] personName:personSomeone5165 age:31
2022-03-04 16:09:23.233740+0800 CoreData实践1[72352:3044306] personName:personSomeone5098 age:40
2022-03-04 16:09:23.233823+0800 CoreData实践1[72352:3044306] personName:personSomeone5643 age:61
分页查询
分页数据,emmm,数据量又不够了,所以我们向数据中多添加一些数据,这个过程同样不赘述了。
- (void)pagingQueryData{
//创建请求对象(填入的是表名称)
NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
//每页显示8条数据
request.fetchLimit = 8;
//跳过数据量
request.fetchOffset = 0;
//创建一个error用于接收错误,如果有错误的话。
NSError* error = nil;
//创建一个数组用于接收查询到的数据对象
NSArray* resultArray = [self.context executeFetchRequest:request error:&error];
if (error) {
NSLog(@"查询失败,错误信息:%@",error);
}else{
NSLog(@"查询结果如下");
for (Person* person in resultArray) {
NSLog(@"personName:%@ age:%lld",person.name,person.age);
}
}
}
运行代码:
2022-03-04 16:27:23.550483+0800 CoreData实践1[72820:3059276] 查询结果如下
2022-03-04 16:27:23.550997+0800 CoreData实践1[72820:3059276] personName:personSomeone8011 age:92
2022-03-04 16:27:23.551868+0800 CoreData实践1[72820:3059276] personName:personSomeone5165 age:31
2022-03-04 16:27:23.552171+0800 CoreData实践1[72820:3059276] personName:personSomeone4661 age:1
2022-03-04 16:27:23.552477+0800 CoreData实践1[72820:3059276] personName:personSomeone5009 age:0
2022-03-04 16:27:23.552932+0800 CoreData实践1[72820:3059276] personName:personSomeone5947 age:85
2022-03-04 16:27:23.553361+0800 CoreData实践1[72820:3059276] personName:personSomeone7893 age:71
2022-03-04 16:27:23.553687+0800 CoreData实践1[72820:3059276] personName:personSomeone5098 age:40
2022-03-04 16:27:23.554317+0800 CoreData实践1[72820:3059276] personName:personSomeone4730 age:26
从运行结果中可以看到获取的数据量已经被限定在8个条数了,如果要看第二页数据,则:
request.fetchOffset = 8;
如果要看第三页数据,则:
request.fetchOffset = 16;
如此类推。