iOS CoreData 编程 iOS Sqlite数据库 iOS 网络编程 iOS CoreData 编程 内容概述 CoreData简介 使用Xcode模板创建CoreData项目 使用CoreData实现数据的增、删、查、改 CoreData数据在UITableView中展现 23.1 CoreData简介 传统的编程中我们使用普通文件或者Sqlite数据库保存数据,普通文件给查询数据带来不便,而Sqlite数据库对于没有数据库经验的程序员来说也是一种挑战。 苹果在SDK3.0之后提供了CoreData框架,这可以说给程序员们带来了福音。CoreData框架以面向对象的方式来操作数据库。后台的数据库对于程序是完全透明的,即使你不懂数据库也不懂SQL语句也可以开发出像样的基于数据库的应用程序。 使用CoreData框架编程时,几个核心的类是必须要掌握的,它们是: NSPersistentStoreCoordinator,持久存储调停者,是应用程序和物理数据库之间的桥梁。 NSManagedObjectContext,管理对象上下文,是程序员和应用程序之间的桥梁,使用该上下文可以实现数据的增、删、查、改功能。 NSManagedObjectModel管理对象模型,映射数据库中表结构。 NSManagedObject管理对象,映射表中的一行。 NSEntityDescription,实体描述类,关联数据库中的表,实例化表中的一个对象是使用。 NSFetchRequest,查询请求类,在查询时使用。 NSPredicate,定义查询条件。 NSSortDescriptor,排序描述符。 下面我们分析一下这些类之间的关系: 物理文件、持久存储和上下文之间的关系。 下图是查询和条件及排序直接的关系。 23.2 使用Xcode模板创建CoreData项目 进行CoreData的基本配置也是一个繁琐的过程,幸好Xcode提供了创建CoreData项目的模板。使用Xcode模板创建项目的过程如下: 启动Xcode创建一个空项目。 在下一步的对话框中选择"Use Core Data"选项。 在代理的头文件中生产了如下代码。 #import <UIKit/UIKit.h> @interface AmakerAppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; // 管理上下文 @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; // 管理对象模型 @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; // 持久存储 @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; // 保存上下文 - (void)saveContext; // 应用程序文档目录 - (NSURL *)applicationDocumentsDirectory; @end 这里声明了管理对象上下文属性、管理对象模型属性、持久存储属性、保存上下文方法和获得应用程序文档目录的方法。 下面是.m文件中的实现。 4.1 获得sqlite数据库保存路径方法 // 返回应用程序路径 - (NSURL *)applicationDocumentsDirectory { // 应用程序路径 return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; } 4.2 实例化持久存储,并建立持久存储和物理文件之间的关系。 // 根据物理文件的位置,获得持久存储 - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (\_persistentStoreCoordinator != nil) { return \_persistentStoreCoordinator; } // 找到物理文件的位置 NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"chapter23\_01.sqlite"]; NSError *error = nil; // 实例化持久存储 \_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; // 建立持久存储和物理文件之间的关联 if (![\_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return \_persistentStoreCoordinator; } 4.3 实例化管理对象模型 // 如果管理对象模型不存在,则从应用程序文件中创建它 - (NSManagedObjectModel *)managedObjectModel { if (\_managedObjectModel != nil) { return \_managedObjectModel; } // 获得模型文件的URL NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"chapter23\_01" withExtension:@"momd"]; // 根据URL实例化管理对象模型 \_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return \_managedObjectModel; } 4.4 创建上下文,并绑定持久存储。 // 如果上下文不存在,则创建它并绑定持久存储 - (NSManagedObjectContext *)managedObjectContext { if (\_managedObjectContext != nil) { return \_managedObjectContext; } // 获得持久存储 NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { // 实例化上下文 \_managedObjectContext = [[NSManagedObjectContext alloc] init]; // 设置上下文和持久存储的关系 [\_managedObjectContext setPersistentStoreCoordinator:coordinator]; } return \_managedObjectContext; } 4.5 保存上下文 // 保存上下文 - (void)saveContext { NSError *error = nil; // 管理上下文 NSManagedObjectContext *managedObjectContext = self.managedObjectContext; if (managedObjectContext != nil) { // 在上下文中有改变但是没有保存,则保存 if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } } 4.6 最后是数据模型界面 23.3 使用CoreData实现数据的增、删、查、改 本节我们以客户和订单为模型,使用CoreData框架实现客户和订单数据的增、删、查、改。创建步骤如下: 使用Xcode模板创建一个空项目,并且勾选"Use Core Data"选项。 创建一个CoreData工具类,声明一组维护客户的订单的方法。 #import <Foundation/Foundation.h> @interface CoreDataUtil : NSObject // 添加客户 -(void)addCustomer; // 删除客户 -(void)deleteCustomer; // 更新客户 -(void)updateCustmer; // 查询客户 -(void)queryCustomer; // 添加订单 -(void)addOrder; // 删除订单 -(void)deleteOrder; // 更新订单 -(void)updateOrder; // 查询订单 -(void)queryOrder; // 根据客户查询订单 -(void)queryOrderByCustomer; @end 实现CoreData工具类的初始化方法,该方法从应用程序代理中获得NSManagedObjectContext对象,并赋值给前面声明的静态NSManagedObjectContext实例。 // 声明静态 NSManagedObjectContext static NSManagedObjectContext *context; @implementation CoreDataUtil // 初始化方法 - (id)init { self = [super init]; if (self) { // 从AmakerAppDelegate中获得NSManagedObjectContext实例 if (context==nil) { AmakerAppDelegate *delegate = [UIApplication sharedApplication].delegate; context = delegate.managedObjectContext; } } return self; } 添加客户的实现,添加客户使用NSEntityDescription的静态方法insertNewObjectForEntityForName,创建一个客户对象,该方法有两个参数,第一个参数是要创建对象的实体名称,第二个参数是NSManagedObjectContext实例。为客户对象的属性赋值,并调用NSManagedObjectContext的save方法保存对象到数据库。 // 添加客户 -(void)addCustomer{ // 使用NSEntityDescription的静态方法insertNewObjectForEntityForName,创建一个客户对象 Customer *c = [NSEntityDescription insertNewObjectForEntityForName:@"Customer" inManagedObjectContext:context]; if (c!=nil) { // 为客户属性赋值 c.age = [NSNumber numberWithInt:20]; c.name = @"tom"; // 使用NSManagedObjectContext保存客户 BOOL result = [context save:nil]; // 判断是否保存成功 if (result) { NSLog(@"Save OK!"); }else{ NSLog(@"Save Fail!"); } } } 删除客户,删除客户首先查询到要删除的客户,查询使用NSManagedObjectContext对象的executeFetchRequest方法,该方法需要一个NSFetchRequest对象,该对象可以直接实例化,并为其指定要查询的实体对象,即NSEntityDescription实例。查询到该对象后,调用NSManagedObjectContext对象的delete方法删除对象,并调用save方法保存。 // 删除客户 -(void)deleteCustomer{ [self addCustomer]; // 实例化NSFetchRequest,用来查询 NSFetchRequest *request = [[NSFetchRequest alloc]init]; // 通过实体名称实例化NSEntityDescription对象 NSEntityDescription *c = [NSEntityDescription entityForName:@"Customer" inManagedObjectContext:context]; // 设置查询对象 [request setEntity:c]; // 进行查询 NSArray *customers = [context executeFetchRequest:request error:nil]; // 如果查询结果大于0,获得第一个对象,并删除 if ([customers count]>0) { // 获得集合中的第一个对象 Customer *c1 = [customers objectAtIndex:0]; // 删除之 [context deleteObject:c1]; // 保存 BOOL result = [context save:nil]; // 判断结果 if (result) { NSLog(@"Delete OK!"); }else{ NSLog(@"Delete Fail!"); } } } 更新客户,和查询类似,首先查询到要更新的对象,重新设置属性,并调用save方法保存 -(void)updateCustmer{ [self addCustomer]; // 实例化NSFetchRequest对象 NSFetchRequest *request = [[NSFetchRequest alloc]init]; // 获得NSEntityDescription实例 NSEntityDescription *c = [NSEntityDescription entityForName:@"Customer" inManagedObjectContext:context]; // 设置查询实体 [request setEntity:c]; // 执行查询 NSArray *customers = [context executeFetchRequest:request error:nil]; if ([customers count]>0) { Customer *c1 = [customers objectAtIndex:0]; // 重新设置属性 [c1 setAge:[NSNumber numberWithInt:100]]; [c1 setName:@"new name"]; // 保存 BOOL result = [context save:nil]; // 判断结果 if (result) { NSLog(@"update OK!"); }else{ NSLog(@"update Fail!"); } } } 订单的添加、删除、修改都和客户维护一致,这里不再赘述,下面来看,根据客户条件查询订单。这里使用NSPredicate指定查询条件。这里使用该实例的predicateWithFormat格式化方法指定查询条件。 // 根据客户,条件查询订单 -(void)queryOrderByCustomer{ // 实例化NSFetchRequest NSFetchRequest *request = [[NSFetchRequest alloc]init]; // 根据实体类名称,获得NSEntityDescription实例 NSEntityDescription *c = [NSEntityDescription entityForName:@"Customer" inManagedObjectContext:context]; // 设置查询实体 [request setEntity:c]; // 执行查询,获得第一个客户 NSArray *customers = [context executeFetchRequest:request error:nil]; Customer *c1; if ([customers count]>0) { c1 = [customers objectAtIndex:0]; } // 实例化NSFetchRequest NSFetchRequest *request2 = [[NSFetchRequest alloc]init]; // 根据实体类名称,获得NSEntityDescription实例 NSEntityDescription *o = [NSEntityDescription entityForName:@"Order" inManagedObjectContext:context]; // 实例化NSPredicate NSPredicate *p = [NSPredicate predicateWithFormat:@"customer=%@",c1]; // 为请求指定条件 request2.predicate = p; // 设置查询实体 [request2 setEntity:o]; //执行查询 NSArray *orders = [context executeFetchRequest:request error:nil]; // 遍历,输出 for(Order *o in orders){ NSLog(@"%@",o.name); } } 在xib文件中添加若干按钮,添加单击事件方法,调用CoreData工具类方法,查看执行结果。 23.4 CoreData数据在UITableView中展现 本节在上一节的基础之上,增加UI界面,使用UITableView来可视化的维护数据。在xib文件中添加UITableView,使用该视图展示数据,另外,在导航栏增加添加和删除按钮。点击按钮添加或删除数据。我们先来看一下程序的运行结果一睹为快吧。 程序的实现步骤如下: 创建一个项目,在界面上添加一个UITableView,并在导航栏上添加两个按钮。 在.h控制器中实现UITableViewDataSource、UITableViewDelegate和UIAlertViewDelegate协议,添加CoreData工具类属性、数据源属性、表格视图属性和添加删除按钮。 #import <UIKit/UIKit.h> #import "CoreDataUtil.h" // 实现UITableViewDataSource、UITableViewDelegate和UIAlertViewDelegate协议 @interface AmakerRootViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,UIAlertViewDelegate> // CoreData工具类 @property(nonatomic,strong)CoreDataUtil *util; // 数据源 @property(nonatomic,strong)NSMutableArray *dataSource; // 表格视图 @property (strong, nonatomic) IBOutlet UITableView *tableView; // 添加删除按钮 @property(nonatomic,strong)UIBarButtonItem *addItem,*delItem; @end 在viewDidLoad方法中,实例化CoreDataUtil,根据查询客户列表数组初始化数据源,实例化添加、删除按钮。 - (void)viewDidLoad { [super viewDidLoad]; // 实例化CoreDataUtil self.util = [[CoreDataUtil alloc]init]; // 查询客户列表 NSArray *array = [self.util queryCustoer]; // 初始化数据源 self.dataSource = [NSMutableArray arrayWithArray:array]; // 实例化添加、删除按钮 self.addItem = [[UIBarButtonItem alloc]initWithTitle:@"Add" style:UIBarButtonItemStylePlain target:self action:@selector(add)]; self.navigationItem.rightBarButtonItem = self.addItem; self.delItem = [[UIBarButtonItem alloc]initWithTitle:@"Del" style:UIBarButtonItemStylePlain target:self action:@selector(del)]; self.navigationItem.leftBarButtonItem = self.delItem; } 点击添加按钮,显示添加客户对话框,设置对话框属性,使得用户可以输入客户名称。 // 添加方法 -(void)add{ // 显示对话框 UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Add Customer" message:nil delegate:self cancelButtonTitle:@"Add" otherButtonTitles:nil, nil]; alert.alertViewStyle = UIAlertViewStylePlainTextInput; [alert show]; } 点击删除按钮,设置表格视图的编辑属性。 // 删除方法,设置编辑属性 -(void)del{ if (![self.tableView isEditing]) { self.delItem.title=@"Done"; [self.tableView setEditing:YES]; }else{ self.delItem.title=@"Del"; [self.tableView setEditing:NO]; } } 在表格视图代理的commitEditingStyle方法中删除客户信息,首先获得要删除的客户信息,从数据源删除数据,从数据库删除数据,重新加载表视图。 // 删除数据 -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{ // 获得当前数据 Customer *c = [self.dataSource objectAtIndex:[indexPath row]]; // 从数据源数组删除 [self.dataSource removeObject:c]; // 从数据库删除 [self.util deleteCustomer:c]; // 重新加载表视图 [self.tableView reloadData]; } 实现对话框的代理方法,通过判断按钮标题添加或更新客户信息。获得输入框内容,调用CoreData工具类来实现添加或删除。 // 对话框代理方法,实现添加数据 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ // 获得按钮标题 NSString *title = [alertView buttonTitleAtIndex:0]; // 获得输入框 UITextField *nameTf = [alertView textFieldAtIndex:0]; // 获得输入框内容 NSString *name = nameTf.text; // 添加 if ([title isEqualToString:@"Add"]) { [self.util addCustomer:name]; }else{ // 更新 self.currentCustomer.name = name; [self.util updateCustomer:self.currentCustomer]; } // 重新加载表视图 [self.tableView reloadData]; } 实现表格视图的数据源方法,根据客户列表数,返回表格行数,获得表格单元。 // 根据客户列表数,返回表格行数 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ NSArray *array = [self.util queryCustoer]; self.dataSource = [NSMutableArray arrayWithArray:array]; return [self.dataSource count]; } // 获得表格单元 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cid"]; if (cell==nil) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cid"]; } Customer *c = [self.dataSource objectAtIndex:[indexPath row]]; cell.textLabel.text = c.name; return cell; } 实现选中行,编辑客户信息功能,弹出对话框,显示要更新的数据。 // 选中行,修改客户信息 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ // 弹出对话框,显示要更新的数据 UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Update Customer" message:nil delegate:self cancelButtonTitle:@"Update" otherButtonTitles:nil, nil]; alert.alertViewStyle = UIAlertViewStylePlainTextInput; UITextField *nameTf = [alert textFieldAtIndex:0]; Customer *c = [self.dataSource objectAtIndex:[indexPath row]]; self.currentCustomer = c; nameTf.text = c.name; [alert show]; } iOS Sqlite数据库 iOS 网络编程