iOS App中数据管理框架Core Data的基本数据操作教程
nsentitydescription是实体描述对象,它可以类比如数据库中的表,nsentitydescription存放的是表的结构信息。这些类都是一些抽象的结构类,并不存储实际每条数据的信息,具体的数据由nsmanagedobject类来描述,我们一般会将实体类化继承于nsmanagedobject。
xocde工具提供了快捷的实体类化功能,还拿我们一开始创建的班级与学生实体来演示,点击.xcdatamodeld文件,点击xcode工具上方导航栏的editor标签,选择creat nsmanagedobject subclass选项,在弹出的窗口中勾选要类化的实体,如下图:
这时,xcode会自动为我们创建一个文件,这些文件中有各个类中属性的声明。
一、创建一条数据
使用如下代码进行数据的创建:
//读取数据模型文件
找到在打印出的路径,会发现里面多了一个sqlite文件,其中有一张表中添加进了一条数据。
nsurl *modelurl = [[nsbundle mainbundle]urlforresource:@"model" withextension:@"momd"];
//创建数据模型
nsmanagedobjectmodel * mom = [[nsmanagedobjectmodel alloc]initwithcontentsofurl:modelurl];
//创建持久化存储协调者
nspersistentstorecoordinator * psc = [[nspersistentstorecoordinator alloc]initwithmanagedobjectmodel:mom];
//数据库保存路径
nsurl * path =[nsurl fileurlwithpath:[[nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes)lastobject] stringbyappendingpathcomponent:@"coredataexample.sqlite"]];
//为持久化协调者添加一个数据接收栈
/*
可以支持的类型如下:
nsstring * const nssqlitestoretype;//sqlite
nsstring * const nsxmlstoretype;//xml
nsstring * const nsbinarystoretype;//二进制
nsstring * const nsinmemorystoretype;//内存
*/
[psc addpersistentstorewithtype:nssqlitestoretype configuration:nil url:path options:nil error:nil];
//创建数据管理上下文
nsmanagedobjectcontext * moc = [[nsmanagedobjectcontext alloc]initwithconcurrencytype:nsmainqueueconcurrencytype];
//关联持久化协调者
[moc setpersistentstorecoordinator:psc];
//创建数据对象
/*
数据对象的创建是通过实体名获取到的
*/
schoolclass * models = [nsentitydescription insertnewobjectforentityforname:@"schoolclass" inmanagedobjectcontext:moc];
//对数据进行设置
models.name = @"第一班";
models.stunum = @60;
//进行存储
if ([moc save:nil]) {
nslog(@"新增成功");
}
nslog(@"%@",[[nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes)lastobject] stringbyappendingpathcomponent:@"coredataexample.sqlite"]);
二、查询数据
coredata中通过查询请求来对数据进行查询操作,查询请求由nsfetchrequest来进行管理和维护。
nsfetchrequest主要提供两个方面的查询服务:
1.提供范围查询的相关功能
2.提供查询结果返回类型与排序的相关功能
nsfetchrequest中常用方法如下:
//创建一个实体的查询请求 可以理解为在某个表中进行查询
+ (instancetype)fetchrequestwithentityname:(nsstring*)entityname;
//查询条件
@property (nullable, nonatomic, strong) nspredicate *predicate;
//数据排序
@property (nullable, nonatomic, strong) nsarray<nssortdescriptor *> *sortdescriptors;
//每次查询返回的数据条数
@property (nonatomic) nsuinteger fetchlimit;
//设置查询到数据的返回类型
/*
typedef ns_options(nsuinteger, nsfetchrequestresulttype) {
nsmanagedobjectresulttype = 0x00,
nsmanagedobjectidresulttype = 0x01,
nsdictionaryresulttype ns_enum_available(10_6,3_0) = 0x02,
nscountresulttype ns_enum_available(10_6,3_0) = 0x04
};
*/
@property (nonatomic) nsfetchrequestresulttype resulttype;
//设置查询结果是否包含子实体
@property (nonatomic) bool includessubentities;
//设置要查询的属性值
@property (nullable, nonatomic, copy) nsarray *propertiestofetch;
在schoolclass实体中查询数据,使用如下的代码:
//创建一条查询请求
nsfetchrequest * request = [nsfetchrequest fetchrequestwithentityname:@"schoolclass"];
//设置条件为 stunum=60的数据
[request setpredicate:[nspredicate predicatewithformat:@"stunum == 60"]];
//进行查询操作
nsarray * res = [moc executefetchrequest:request error:nil];
nslog(@"%@",[res.firstobject stunum]);
进行数据初始化
nsfetchedresultscontroller的初始化需要一个查询请求和一个数据操作上下文。代码示例如下:
//遵守协议
@interface viewcontroller ()<nsfetchedresultscontrollerdelegate>
{
//数据桥接对象
nsfetchedresultscontroller * _feccon;
}
@end
@implementation viewcontroller
- (void)viewdidload {
用于初始化nsfecthedresultscontroller的数据请求对象必须设置一个排序规则。在initwithfetchrequest:managedobjectcontext:sectionnamekeypath:cachename:方法中,如果设置第三个参数,则会以第三个参数为键值进行数据的分区。当数据发生变化时,将通过代理进行方法的回调。
[super viewdidload];
//进行初始化操作
nsurl *modelurl = [[nsbundle mainbundle]urlforresource:@"model" withextension:@"momd"];
nsmanagedobjectmodel * mom = [[nsmanagedobjectmodel alloc]initwithcontentsofurl:modelurl];
nspersistentstorecoordinator * psc = [[nspersistentstorecoordinator alloc]initwithmanagedobjectmodel:mom];
nsurl * path =[nsurl fileurlwithpath:[[nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes)lastobject] stringbyappendingpathcomponent:@"coredataexample.sqlite"]];
[psc addpersistentstorewithtype:nssqlitestoretype configuration:nil url:path options:nil error:nil];
nsmanagedobjectcontext * moc = [[nsmanagedobjectcontext alloc]initwithconcurrencytype:nsmainqueueconcurrencytype];
[moc setpersistentstorecoordinator:psc];
nsfetchrequest * request = [nsfetchrequest fetchrequestwithentityname:@"schoolclass"];
//设置数据排序
[request setsortdescriptors:@[[nssortdescriptor sortdescriptorwithkey:@"stunum" ascending:yes]]];
//进行数据桥接对象的初始化
_feccon = [[nsfetchedresultscontroller alloc]initwithfetchrequest:request managedobjectcontext:moc sectionnamekeypath:nil cachename:nil];
//设置代理
_feccon.delegate=self;
//进行数据查询
[_feccon performfetch:nil];
}
@end
三、与uitableview进行数据绑定
-(uitableviewcell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath{
效果如下:
uitableviewcell * cell = [tableview dequeuereusablecellwithidentifier:@"cellid"];
if (!cell) {
cell = [[uitableviewcell alloc]initwithstyle:uitableviewcellstylesubtitle reuseidentifier:@"cellid"];
}
//获取相应数据模型
schoolclass * obj = [_feccon objectatindexpath:indexpath];
cell.textlabel.text = obj.name;
cell.detailtextlabel.text = [nsstring stringwithformat:@"有%@人",obj.stunum];
return cell;
}
-(nsinteger)numberofsectionsintableview:(uitableview *)tableview{
return [_feccon sections].count;
}
-(nsinteger)tableview:(uitableview *)tableview numberofrowsinsection:(nsinteger)section{
id<nsfetchedresultssectioninfo> info = [_feccon sections][section];
return [info numberofobjects];
}
四、将数据变化映射到视图
//数据将要改变时调用的方法
- (void)controllerwillchangecontent:(nsfetchedresultscontroller *)controller
{
//开启tableview更新预处理
[[self tableview] beginupdates];
}
//分区数据改变时调用的方法
- (void)controller:(nsfetchedresultscontroller *)controller didchangesection:(id <nsfetchedresultssectioninfo>)sectioninfo atindex:(nsuinteger)sectionindex forchangetype:(nsfetchedresultschangetype)type
{
//判断行为类型
switch(type) {
//插入新分区
case nsfetchedresultschangeinsert:
[[self tableview] insertsections:[nsindexset indexsetwithindex:sectionindex] withrowanimation:uitableviewrowanimationfade];
break;
//删除分区
case nsfetchedresultschangedelete:
[[self tableview] deletesections:[nsindexset indexsetwithindex:sectionindex] withrowanimation:uitableviewrowanimationfade];
break;
//移动分区
case nsfetchedresultschangemove:
//更新分区
case nsfetchedresultschangeupdate:
break;
}
}
//数据改变时回调的代理
- (void)controller:(nsfetchedresultscontroller *)controller didchangeobject:(id)anobject atindexpath:(nsindexpath *)indexpath forchangetype:(nsfetchedresultschangetype)type newindexpath:(nsindexpath *)newindexpath
{
switch(type) {
//插入数据
case nsfetchedresultschangeinsert:
[[self tableview] insertrowsatindexpaths:@[newindexpath] withrowanimation:uitableviewrowanimationfade];
break;
//删除数据
case nsfetchedresultschangedelete:
[[self tableview] deleterowsatindexpaths:@[indexpath] withrowanimation:uitableviewrowanimationfade];
break;
//更新数据
case nsfetchedresultschangeupdate:
[self reloaddata];
break;
//移动数据
case nsfetchedresultschangemove:
[[self tableview] deleterowsatindexpaths:@[indexpath] withrowanimation:uitableviewrowanimationfade];
[[self tableview] insertrowsatindexpaths:@[newindexpath] withrowanimation:uitableviewrowanimationfade];
break;
}
}
//数据更新结束调用的代理
- (void)controllerdidchangecontent:(nsfetchedresultscontroller *)controller
{
[[self tableview] endupdates];
}