首先在创建项目的时候最好可以直接勾上 use
如果没勾上的话,可以新建一个带Coredata的新项目,看看都多了些什么东西
首先多了一个
这玩意可以自己新建,它是一个DataModel
然后就是AppDelegate多了一些CoreData要用到的一些函数,我大概截个图,Xcode都自动加上了pragma,非常容易分辨
如果不想重新建项目的话,自己复制粘贴一下就好。
另外,如果不是预设的名字,在AppDelegate中声明的保存数据等函数中,有以名字实体名作为函数参数的,一定要仔细看一下AppDelegate中的函数参数,避免因为不是预设而连不上数据库。
这些属性是NSURL类型的,是指向数据库地址的,可以通过查NSURL类型的数据来看看有没有错。
同时也可以在查到NSURL后将它打印出来,或者通过其他方式获取,这样就可以通过SQLite的一些软件去管理数据库,例如
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoredataDemo.sqlite"]; NSLog(@"%@",storeURL);
在我们存数据时就可以得到输出
2016-01-31 22:42:51.995 CoredataDemo[4597:804629] file:///Users/suntian/Library/Developer/CoreSimulator/Devices/81AE7359-7F19-4634-BBF2-CBA057017373/data/Containers/Data/Application/38AD61EF-493F-4E67-915E-E6940D23E5B7/Documents/CoredataDemo.sqlite
这地址就是数据库的地址了
接下来是如何使用数据库
首先,打开DataModel,这是一个要用到的数据库
在这里 可以新建Entity(实体),接着在实体中继续添加想要的数据类型
接着添加一个用以控制一个Entity的Model,同样新建文件,选CoreData类中的NSManagedObjectSubclass,图就不上了
Xcode会两次问你,要控制哪个数据库的哪个Entity,选中即可,生成了四个文件
接着,在你要用的地方添加model,活动在Viewcontroller中,所以在Viewcontroller中添加
@property Entity *entity;
entity的构造可以采用延时构造,并且这样也的确方便
构造时,将不采用init,因为,entity是一个Entity属性的值,它要连接数据库中定义的Entity,而不是去初始化这个属性,所以这里的构造要去连接之前在DataModel中定义的Entity
-(Entity *)entity { if(!_entity) { _entity = [NSEntityDescription insertNewObjectForEntityForName:@"Entity" inManagedObjectContext:self.context]; } return _entity; }
这里用到了一个 self.context ,context是一个在AppDelegate中定义的属性,它是NSManagedObjectContext类型,在保存数据至数据库时候我们会用到它,具体类型的详细解释可以看一下文档,下面贴出AppDelegate中为CoreData写好的保存函数,就可以看出context的用处
- (void)saveContext { NSManagedObjectContext *managedObjectContext = self.managedObjectContext; if (managedObjectContext != nil) { NSError *error = nil; if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { // Replace this implementation with code to handle the error appropriately. // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } }
所以我们需要在Viewcontroller中引入AppDelegate,它为CoreData定义了很多预设的东西我们都要用到,引入头文件以后,我们就需要再定义
@property NSManagedObjectContext *context;
@property AppDelegate *appdelegate;
context我们保存数据要用到 ,通过定义这个appdelegate来调用函数
当我们想保存数据时,就先赋值,再save即可
//伪代码
_entity.data = mydata; [self.appdelegate savecontext];
当然context和appdelegate别忘了定义,同样采用延时构造比较好
-(NSManagedObjectContext *)context { return self.appdelegate.managedObjectContext; } -(AppDelegate *)appdelegate { if (!_appdelegate) { _appdelegate = [UIApplication sharedApplication].delegate; } return _appdelegate; }
appdelegate的构造是返回当前进程的delegate
具体什么时候进行这个操作,就看你什么时候获取到了数据,是获取到数据时存数据库或者其他时候,都是自己来决定了。
举个栗子,我有两个按钮,想在按下的时候存点东西进去
-(IBAction)InButtonPressed:(UIButton*)sender { if(sender == _inview.BTIn0) { NSLog(@"0"); NSNumber *numb; numb = [NSNumber numberWithInt:0]; _entity.date = [NSDate date]; _entity.attribute = numb; [self.appdelegate saveContext]; } else if(sender == _inview.BTIn1) { NSLog(@"1"); NSNumber *numb; numb = [NSNumber numberWithInt:1]; _entity.date = [NSDate date]; _entity.attribute = numb; [self.appdelegate saveContext]; } }
这样就完成了写库的操作。
但是这个时候,数据库里只会有一条数据发生改变,即entity实际指向的就是那一条数据,不论我按0或者1,都只会保存我上一次按下的数,比如按0,数据中只会有1个0,我再按1,这个0就会变成1而不是添加一条新的1。
后来做如下修改
-(IBAction)InButtonPressed:(UIButton*)sender { Entity *addentity; addentity = [NSEntityDescription insertNewObjectForEntityForName:@"Entity" inManagedObjectContext:self.context]; if(sender == _inview.BTIn0) { NSLog(@"0"); NSNumber *numb; numb = [NSNumber numberWithInt:0]; addentity.date = [NSDate date]; addentity.attribute = numb; [self.appdelegate saveContext]; } else if(sender == _inview.BTIn1) { NSLog(@"1"); NSNumber *numb; numb = [NSNumber numberWithInt:1]; addentity.date = [NSDate date]; addentity.attribute = numb; [self.appdelegate saveContext]; } // if(sender == _inview.BTIn0) // { // NSLog(@"0"); // NSNumber *numb; // numb = [NSNumber numberWithInt:0]; // self.entity.date = [NSDate date]; // self.entity.attribute = numb; // [self.appdelegate saveContext]; // } // else if(sender == _inview.BTIn1) // { // NSLog(@"1"); // NSNumber *numb; // numb = [NSNumber numberWithInt:1]; // self.entity.date = [NSDate date]; // self.entity.attribute = numb; // [self.appdelegate saveContext]; // } }
在这种情况下,把之前用到的entity所有相关的定义删除也可,因为已经没在用到了,这个时候的savecontext也会把数据存下了,至于为什么savecontext能存下数据并且建立了一条新的?
在http://blog.csdn.net/swj6125/article/details/9969591 中,这篇博文打算存数条数据,而这个作者罗列了相当多的数据来赋值,而最后只用了一条saveContext。
所以我猜测,saveContext可以将所有指向了数据库的指针内容进行保存,而我在按键事件内进行的定义,相当于每次都是一个新的Entity,所以每次都会给我一条新的数据。
saveContext的代码如下
- (void)saveContext { NSManagedObjectContext *managedObjectContext = self.managedObjectContext; if (managedObjectContext != nil) { NSError *error = nil; if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { // Replace this implementation with code to handle the error appropriately. // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } }
目前还没有在文档中发现有关说明,发现后会补上。
存完数据以后我们还需要的就是读数据
读数据比较简单
NSError *error; NSFetchRequest *request=[[NSFetchRequest alloc] init]; NSEntityDescription *entity=[NSEntityDescription entityForName:@"Entity" inManagedObjectContext:self.context]; [request setEntity:entity]; NSArray *results=[[self.context executeFetchRequest:request error:&error] copy];
得到的数组results就是返回的所有数据,进行处理就可以了
栗子
for (Entity *temptntity in results) { NSLog(@"%@ %@",temptntity.date,temptntity.attribute); }