IOS开发(96)之Core Data
core data是一个功能强大的层,位于sqlite之上,它避免了sql的复杂性,能让我们以更自然的方式与数据库进行交互。core data将数据库行转换为oc对象(托管对象)来实现,这样无需任何sql知识就能操作他们。
core data位于mvc设计模式中的模型层,一般需要在设备上存储结构化数据时,考虑使用sqlite或是序列化等方法,而core data是这两种方法的混合体,并增加了一些功能,提供了sql强大威力,但是用起来又和序列化一样简单。core data能将应用程序中的对象直接保存到数据库中,无需进行复杂的查询,也无需确保对象的属性名和数据库字段名对应,这一切都由core data完成。
core data的核心——托管对象
托管对象是要存储到数据库中的对象的一种表示,可以看成是sql记录,它通常包含一些字段,这些字段与应用程序中要存储的对象的属性进行匹配,创建托管对象后,必须将气托管到托管对象上下文中,然后才可以存储到数据库中。
托管对象上下文:
托管对象上下文包含所有的托管对象,这些托管对象已经为提交给数据库准备就绪,在托管对象上下文中,可以添加、修改和删除托管对象,这一层相当于应用程序和数据库之间的缓冲区。
托管对象表:
托管对象表描述了数据库的架构(schema),供托管对象上下文与数据库交互时使用。托管对象表包含一些列实体描述,每个实体都描述了一个数据库表,用于将托管对象映射到数据库条目。
下面来创建一个core data
首先要保证引入了coredata.framwork框架到项目中,然后新建模型文件,new file——core data中的data model,然后命名为cdjournal.xcdatamodel,这里我们做一个简单的记录流水账的程序。
接下来是定义数据库实体,选中cdjournal.xcdatamodel文件打开表编辑器,点击添加一个名为entry的实体,然后可以为实体添加属性并指定属性的数据类型。还可以创建其他实体,如果一个实体包含另一个实体,可通过拖放建立关系,类似于sql外键,比如建立一个author实体可以有多个entry。建立实体及属性如下图:
创建完实体后必须生成表示数据库对象的类,使我们能在代码中表示实体,选择entry实体,然后选择菜单editor——create nsmanagedobject subclass,点击create,就完成了。完成后可以看到工程中多了一个entry的h和m文件,这就是core data模型中的实体对象。基本准备工作就完成了,如下是工程目录:
现在开始编写初始化core data模型的代码
首先,在appdelegate.h中声明core data需要的对象,代码如下:
[cpp] #import <uikit/uikit.h>
//引入coredata框架
#import <coredata/coredata.h>
@classviewcontroller;
@interface appdelegate : uiresponder <uiapplicationdelegate]]>
@property (strong, nonatomic) uiwindow *window;
@property (strong, nonatomic) viewcontroller *viewcontroller;
//数据模型对象
@property(strong,nonatomic) nsmanagedobjectmodel *managedobjectmodel;
//上下文对象
@property(strong,nonatomic) nsmanagedobjectcontext *managedobjectcontext;
//持久性存储区
@property(strong,nonatomic) nspersistentstorecoordinator *persistentstorecoordinator;
//初始化core data使用的数据库
-(nspersistentstorecoordinator *)persistentstorecoordinator;
//managedobjectmodel的初始化赋值函数
-(nsmanagedobjectmodel *)managedobjectmodel;
//managedobjectcontext的初始化赋值函数
-(nsmanagedobjectcontext *)managedobjectcontext;
@end
然后在.m文件中实现定义的方法:
[cpp] -(nsmanagedobjectmodel *)managedobjectmodel
{
if (managedobjectmodel != nil) {
returnmanagedobjectmodel;
}
managedobjectmodel = [[nsmanagedobjectmodel mergedmodelfrombundles:nil] retain];
return managedobjectmodel;
}
-(nspersistentstorecoordinator *)persistentstorecoordinator
{
if (persistentstorecoordinator != nil) {
returnpersistentstorecoordinator;
}
//得到数据库的路径
nsstring *docs = [nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes) lastobject];
//coredata是建立在sqlite之上的,数据库名称需与xcdatamodel文件同名
nsurl *storeurl = [nsurl fileurlwithpath:[docs stringbyappendingpathcomponent:@"cdjournal.sqlite"]];
nserror *error = nil;
persistentstorecoordinator = [[nspersistentstorecoordinator alloc]initwithmanagedobjectmodel:[self managedobjectmodel]];
if (![persistentstorecoordinator addpersistentstorewithtype:nssqlitestoretype configuration:nil url:storeurl options:nil error:&error]) {
nslog(@"error: %@,%@",error,[error userinfo]);
}
returnpersistentstorecoordinator;
}
-(nsmanagedobjectcontext *)managedobjectcontext
{
if (managedobjectcontext != nil) {
return managedobjectcontext;
}
nspersistentstorecoordinator *coordinator =[self persistentstorecoordinator];
if (coordinator != nil) {
managedobjectcontext = [[nsmanagedobjectcontext alloc]init];
[managedobjectcontext setpersistentstorecoordinator:coordinator];
}
return managedobjectcontext;
}
另外,为了保证需要存储的数据不丢失,添加如下代码:
[cpp] //这个方法定义的是当应用程序退到后台时将执行的方法,按下home键执行(通知中心来调度)
//实现此方法的目的是将托管对象上下文存储到数据存储区,防止程序退出时有未保存的数据
- (void)applicationwillterminate:(uiapplication *)application
{
nserror *error;
if (managedobjectcontext != nil) {
//haschanges方法是检查是否有未保存的上下文更改,如果有,则执行save方法保存上下文
if ([managedobjectcontext haschanges] && ![managedobjectcontext save:&error]) {
nslog(@"error: %@,%@",error,[error userinfo]);
abort();
}
}
}
然后对xib文件进行布局并连接iboutlet和ibaction
viewcontroller.h代码如下:
[cpp] #import <uikit/uikit.h>
#import "appdelegate.h"
@interface viewcontroller : uiviewcontroller
@property (retain, nonatomic) iboutletuitextfield *titletextfield;
@property (retain, nonatomic) iboutletuitextfield *contenttextfield;
@property (strong,nonatomic) appdelegate *mydelegate;
@property (strong,nonatomic) nsmutablearray *entries;
//单击按钮后执行数据保存操作
- (ibaction)addtodb:(id)sender;
//单击按钮后执行查询操作
- (ibaction)queryfromdb:(id)sender;
//当通过键盘在uitextfield中输入完毕后,点击屏幕空白区域关闭键盘的操作
-(ibaction)backgroundtapped:(id)sender;
@end
viewcontroller.m代码如下:
[cpp] #import "viewcontroller.h"
#import "entry.h"
@interfaceviewcontroller ()
@end
@implementation viewcontroller
@synthesize titletextfield;
@synthesize contenttextfield;
@synthesize mydelegate = _mydelegate;
@synthesize entries = _entries;
- (void)viewdidload
{
[superviewdidload];
//获取当前应用程序的委托(uiapplication sharedapplication为整个应用程序上下文)
self.mydelegate = (appdelegate *)[[uiapplication sharedapplication] delegate];
}
- (void)viewdidunload
{
[selfsettitletextfield:nil];
[selfsetcontenttextfield:nil];
[superviewdidunload];
// release any retained subviews of the main view.
}
- (bool)shouldautorotatetointerfaceorientation:(uiinterfaceorientation)interfaceorientation
{
return (interfaceorientation != uiinterfaceorientationportraitupsidedown);
}
- (void)dealloc {
[titletextfieldrelease];
[contenttextfieldrelease];
[superdealloc];
}
//单击按钮后执行数据保存操作
- (ibaction)addtodb:(id)sender {
//让coredata在上下文中创建一个新对象(托管对象)
entry *entry = (entry *)[nsentitydescription insertnewobjectforentityforname:@"entry" inmanagedobjectcontext:self.mydelegate.managedobjectcontext];
[entry settitle:self.titletextfield.text];
[entry setbody:self.contenttextfield.text];
[entry setcreationdate:[nsdatedate]];
nserror *error;
//托管对象准备好后,调用托管对象上下文的save方法将数据写入数据库
bool issavesuccess = [self.mydelegate.managedobjectcontextsave:&error];
if (!issavesuccess) {
nslog(@"error: %@,%@",error,[error userinfo]);
}else {
nslog(@"save successful!");
}
}
//单击按钮后执行查询操作
- (ibaction)queryfromdb:(id)sender {
//创建取回数据请求
nsfetchrequest *request = [[nsfetchrequest alloc] init];
//设置要检索哪种类型的实体对象
nsentitydescription *entity = [nsentitydescription entityforname:@"entry"inmanagedobjectcontext:self.mydelegate.managedobjectcontext];
//设置请求实体
[request setentity:entity];
//指定对结果的排序方式
nssortdescriptor *sortdescriptor = [[nssortdescriptor alloc] initwithkey:@"creationdate"ascending:no];
nsarray *sortdescriptions = [[nsarray alloc]initwithobjects:sortdescriptor, nil];
[request setsortdescriptors:sortdescriptions];
[sortdescriptions release];
[sortdescriptor release];
nserror *error = nil;
//执行获取数据请求,返回数组
nsmutablearray *mutablefetchresult = [[self.mydelegate.managedobjectcontext executefetchrequest:request error:&error] mutablecopy];
if (mutablefetchresult == nil) {
nslog(@"error: %@,%@",error,[error userinfo]);
}
self.entries = mutablefetchresult;
nslog(@"the count of entry:%i",[self.entriescount]);
for (entry *entry inself.entries) {
nslog(@"title:%@---content:%@---date:%@",entry.title,entry.body,entry.creationdate);
}
[mutablefetchresult release];
[request release];
}
//更新操作
-(void)updateentry:(entry *)entry
{
[entry settitle:self.titletextfield.text];
[entry setbody:self.contenttextfield.text];
[entry setcreationdate:[nsdatedate]];
nserror *error;
bool isupdatesuccess = [self.mydelegate.managedobjectcontextsave:&error ];
if (!isupdatesuccess) {
nslog(@"error:%@,%@",error,[error userinfo]);
}
}
//删除操作
-(void)deleteentry:(entry *)entry
{
[self.mydelegate.managedobjectcontext deleteobject:entry];
[self.entriesremoveobject:entry];
nserror *error;
if (![self.mydelegate.managedobjectcontext save:&error]) {
nslog(@"error:%@,%@",error,[error userinfo]);
}
}
//当通过键盘在uitextfield中输入完毕后,点击屏幕空白区域关闭键盘的操作
-(ibaction)backgroundtapped:(id)sender
{
[titletextfield resignfirstresponder];
[contenttextfield resignfirstresponder];
}
@end
最后运行并填入数据,点击add后添加成功
多添加几条数据后点击query便可以查看输出的查询结果,在命令行的输出结果如下:
推荐阅读
-
IOS开发(41)之关于NSString和NSMutableString的retainCount
-
IOS开发(43)之10个迷惑新手的Cocoa&Objective-c开发问题
-
IOS开发(40)之objective-C 的内存管理之-引用计数
-
IOS开发(42)之IOS设计UI工具大全
-
IOS开发(39)之KVC KVO KVB
-
IOS开发(47)之iOS Block学习
-
IOS开发(59)之Block Object的调用
-
IOS开发(54)之Storyboard之传值
-
IOS开发(48)之由init、loadView、viewDidLoad、viewDidUnload、dealloc的关系说起
-
IOS开发(56)之并发简介