苹果的CoreData框架(不限于)提供了一种数据持久化解决方案,它基于如下结构(图片来源苹果官网):
其中涉及了几个概念:
NSManagedObject: 数据库中一条记录在内存的实例。
NSManagedObjectContext: 若干NSManagedObject在内存中的存在空间,或称上下文。除非该上下文执行save动作,否则数据变动一直限于内存中,并不会保存到文件。
NSManagedObjectModel: 数据库的模型表示,是若干数据表的集合。
NSPersistentObjectCoordinator: 作为中间层,根据NSManagedObjectModel帮我们协调不同格式的存储文件。
这里简单记录下CoreData的增、删、查动作。
首先,创建一个Data Model(一张RandomEvent表,包含两个字段,分别是randomNumber和createDate),并初始化:
- (void)initCoreData
{
if (nil != self.managedObjectContext) {
return ;
}
NSError *error = nil;
NSString *savePath = [NSHomeDirectory() stringByAppendingString:@"/Documents/CDDemo.sqlite"];
NSURL *saveUrl = [NSURL fileURLWithPath:savePath];
NSManagedObjectModel *mom = [NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:saveUrl options:nil error:&error]) {
NSLog(@"Error: %@", [error localizedDescription]);
} else {
self.managedObjectContext = [[[NSManagedObjectContext alloc] init] autorelease];
[self.managedObjectContext setPersistentStoreCoordinator:coordinator];
}
[coordinator release], coordinator = nil;
}
这里选择的是sqlite格式。
接着,提供一个UITableView以供展示,和两个按钮来响应增删动作。如下图:
点击Add按钮,会生成一个随机数,将这个随机数和生成的时间一起写入数据库。
同时,当增加的记录条数够多的时候,UITableView会定位到新增记录。
- (void)onAddButtonItem:(id)sender
{
RandomEvent *randomEvent = (RandomEvent *)[NSEntityDescription insertNewObjectForEntityForName:@"RandomEvent" inManagedObjectContext:self.managedObjectContext];
randomEvent.createDate = [NSDate date];
randomEvent.randomNumber = [NSNumber numberWithInt:arc4random() % 100];
[self saveContext];
[self refreshEventsList];
if (1) {
//tableView is not enough for the list to show
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:([self.fetchEventsResult count] - 1) inSection:0];
[self.eventTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
对NSManagedObjectContext的操作只是在内存中进行,需要执行save动作才写到本地文件。
- (BOOL)saveContext
{
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(@"Error: %@", [error localizedDescription]);
return NO;
}
return YES;
}
点击Edit按钮,会让UITableView进入编辑模式,让用户可以删除条目:
- (void)onEditButtonItem:(id)sender
{
if ([self.eventTableView isEditing]) {
UIBarButtonItem *editButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Edit" style:UIBarButtonItemStyleDone target:self action:@selector(onEditButtonItem:)];
self.navigationItem.leftBarButtonItem = editButtonItem;
[editButtonItem release], editButtonItem = nil;
[self.eventTableView setEditing:NO animated:YES];
} else {
UIBarButtonItem *editButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(onEditButtonItem:)];
self.navigationItem.leftBarButtonItem = editButtonItem;
[editButtonItem release], editButtonItem = nil;
[self.eventTableView setEditing:YES animated:YES];
}
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = indexPath.row;
if (row < [self.fetchEventsResult count]) {
[self.managedObjectContext deleteObject:[self.fetchEventsResult objectAtIndex:row]];
[self saveContext];
[self refreshEventsList];
}
}
最后,获取本地数据进行展示:
- (void)fetchEvents
{
NSEntityDescription *entityDesctiption = [NSEntityDescription entityForName:@"RandomEvent" inManagedObjectContext:self.managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entityDesctiption];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"createDate" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release], sortDescriptor = nil;
NSError *error = nil;
self.fetchEventsResult = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (nil == self.fetchEventsResult) {
NSLog(@"Error: %@", [error localizedDescription]);
}
[fetchRequest release], fetchRequest = nil;
}
#pragma mark - UITableView datasource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.fetchEventsResult count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"RandomEventTableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
RandomEvent *randomEvent = (RandomEvent *)[self.fetchEventsResult objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:@"Random Number : %d", [randomEvent.randomNumber intValue]];
return cell;
}