最近几天整了下Sqlite3,也就是iOS的另外一种储存方式,那么coreData是有什么不足么,不是,一般数据比较简易的时候是不会用coreData的,反而会用自身的sqlte3来实现本地的存储,这就需要用到了点SQL语句了,一般都会用第三方FMDB(第三方库)来简化使用,但第三方的应用是下一次博客的事情了,这次用自带的sqlite3来实现一个简易的通讯录,能够实现保存,并完成增删改查即可,毕竟是最基础的嘛,用第三方虽然简单,但是底层的基础还是要回的。首先看一下如何导入自身的sqlite3的库吧
如果细看这个图,那么也就知道,这个demo是按照MVC模式写的,既然是MVC模式写的,那么必然就会出现Model(模型类),View(视图类)以及Controller(控制器类)
这次的页面没有进行细作,只是为了能够了解Sqlite3的用法,首先就是模型类,看看数据库结构
上面是一个第三方工具,虽然能够快速建立表,但是作为程序员,不建议用它直接建表,建议用sql语句,毕竟还能回顾以及锻炼自己的SQL语句嘛,岂不是一举两得,一般工具是用来查看数据库的。
这里的布局非常简单,只是为了介绍sqlite3的用法,如果想要比较好的视觉可以去之前的博客iOS学习-------简单通讯录(UITableView和CoreData的应用),其他的都是一样的,只是存储的方法变了而已
// // Humen.h // Sqilte3 // // Created by YueWen on 15/10/6. // Copyright (c) 2015年 YueWen. All rights reserved. // #import <Foundation/Foundation.h> @interface Humen : NSObject @property(nonatomic,strong)NSString * name;//姓名 @property(nonatomic,assign)NSInteger age;//年龄 @property(nonatomic,strong)NSString * tele;//电话 @property(nonatomic,strong)NSString * address;//地址 @property(nonatomic,assign)NSInteger humenId;//id /** * 便利初始化方法 * * @param name 初始name * @param age 初始age * @param tele 初始tele * @param address 初始地址 * * @return 初始化好的Humen对象 */ -(instancetype)initWithName:(NSString *)name Age:(NSInteger)age Tele:(NSString *)tele Address:(NSString *)address;
-(instancetype)initWithName:(NSString *)name Age:(NSInteger)age Tele:(NSString *)tele Address:(NSString *)address { if (self = [super init]) { self.name = name;//初始化name self.age = age;//初始化age self.tele = tele;//初始化tele self.address = address;//初始化address } return self; }
/** * 增加人 * * @param humen 需要增加的Humen模型 */ -(void)addHumenToSqlite:(Humen *)humen; /** * 更新数据 * * @param humen 需要更新的Humen模型 */ -(void)updateHumenFromSqlite:(Humen *)humen withIndex:(NSInteger)index; /** * 根据下标即id删除 * * @param index 当前的id */ -(void)deleteHumenFromSqlite:(NSInteger)index; /** * 根据姓名查询名字 * * @param name 查询的名字 */ -(void)selectHumenFromWithName:(NSString *)name;
/** * 单例方法 * * @return 返回单例 */ +(instancetype)shareSqlite3Manager;
此外,还应该有一个方法能够加载所有的数据,即刷新类似功能的时候,从新从数据库中加载一般数据
/** * 加载数据库中所有的数据 */ -(void)loadMHumen;
/** * 存储数据库中的数据数组 */ @property(nonatomic,strong,readonly)NSArray * humen;
然后是最麻烦的实现方法,先从最简单的东西开始,不要忘记导入自带的sqlite3的头文件
#import <sqlite3.h>
@interface Sqlite3Manager () @property(nonatomic)sqlite3 * humendate;//不要加strong @property(nonatomic,strong)NSMutableArray * mHumen; @end
- (instancetype)init { self = [super init]; if (self) { //初始化数据数组 self.mHumen = [NSMutableArray array]; //打开数据库 [self openSqlite_db]; //创建表 [self creatSqlite_db]; //加载数据 [self loadMHumen]; } return self; } //单例方法 +(instancetype)shareSqlite3Manager { static Sqlite3Manager * sqliteManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sqliteManager = [[Sqlite3Manager alloc]init]; }); return sqliteManager; }
再用这个苹果打包好的Sqlite3的时候,实时要注意objc对象和C语言类型的转换,因为SQL是用C语言进行操作的,不认NSString等对象,打开数据库如下
/** * 打开数据库 */ -(void)openSqlite_db { //获取沙盒目录 NSString * path1 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; //追加数据库名称 NSString * path = [path1 stringByAppendingPathComponent:@"humen.db"]; //打开数据库 sqlite3_open([path UTF8String],&self->_humendate);//导入的包中的API,因为底层是C语言的东西,所以path需要转成C语言的字符串,后面传一个sqlite3指针的地址 }
/** * 创建本地的sqlite文件数据库,格式为db */ -(void)creatSqlite_db { //创建表的SQL语句,用C语言的字符串,如果用了NSString,记得转成C语言字符串即可 char * createTableSQL = "create table if not exists t_humen (id integer primary key,name varchar(30),age integer,tele varchar(100),address varchar(100))"; //执行,第一个参数是sqlite3对象指针,第二个是C语言类型的SQL语句,后面3个参数填NULL即可 sqlite3_exec(self->_humendate, createTableSQL, NULL, NULL, NULL); }
/** * 加载数据 */ -(void)loadMHumen { //清空之前的所有的数据 [self.mHumen removeAllObjects]; //访问数据库获取数据,根据id,默认为升序 char * selectSQL = "select * from t_humen order by id"; //创建sqlite3_stmt对象 sqlite3_stmt * stmt; //准备加载 /** * 参数的意义: * 1:sqlite3的属性指针 * 2:执行的sql语句 * 3: 这里填的是搜说的字节数,-1表示全部 * 4: 表示填入一个sqlite3_stmt的对象 */ sqlite3_prepare_v2(self->_humendate, selectSQL, -1, &stmt, NULL); //循环加载 while (sqlite3_step(stmt) ==SQLITE_ROW) { //初始化一个Humen对象 Humen * humen = [[Humen alloc] initWithName:[NSString stringWithUTF8String:(char *)(sqlite3_column_text(stmt, 1))]//第一列是名字 Age:sqlite3_column_int(stmt, 2)//第二列是年龄 Tele:[NSString stringWithUTF8String:(char *)(sqlite3_column_text(stmt, 3))]//第三列是电话 Address:[NSString stringWithUTF8String:(char *)(sqlite3_column_text(stmt, 4))]];//第四列是地址 humen.humenId = sqlite3_column_int(stmt, 0); //添加一个数组 [self.mHumen addObject:humen]; } sqlite3_finalize(stmt);//表示完成,回馈一下 }
首先是增加人,如何增加,直接传入一个Humen对象,其他的操作在方法里操作即可,用SQL语句中的insert into
/** * 增加人 * * @param humen 需要增加的Humen模型 */ -(void)addHumenToSqlite:(Humen *)humen { //为数组添加数据 [self.mHumen addObject:humen]; //预编译语句 char * insertSQL = "insert into t_humen values(NULL,?,?,?,?)"; sqlite3_stmt * stmt; //准备 sqlite3_prepare_v2(self->_humendate, insertSQL, -1, &stmt, NULL); //为stmt预编译语句绑定数据,从1开始 sqlite3_bind_text(stmt, 1, [humen.name UTF8String], -1, NULL);//为name绑定 sqlite3_bind_int(stmt, 2, (int)humen.age);//为age绑定 sqlite3_bind_text(stmt, 3, [humen.tele UTF8String], -1, NULL);//为tele绑定 sqlite3_bind_text(stmt, 4, [humen.address UTF8String], -1, NULL);//为address绑定 //单步调试 int rst = sqlite3_step(stmt); if (rst == SQLITE_DONE) { NSLog(@"插入成功!"); }else { NSLog(@"失败!编号为:%d",rst); } sqlite3_finalize(stmt); }
/** * 删除指定id的人对象 * * @param index 下标 + 1 */ -(void)deleteHumenFromSqlite:(NSInteger)index { //获取当前的对象id NSInteger ID = ((Humen *)self.mHumen[index - 1]).humenId; [self.mHumen removeObjectAtIndex:index - 1]; //从数据库中删除 //预编译语句 char * deleteSQL = "delete from t_humen where id=?"; sqlite3_stmt * stmt; //准备 sqlite3_prepare_v2(self.humendate, deleteSQL, -1, &stmt, NULL); //绑定数据 sqlite3_bind_int(stmt, 1, (int)ID); //分布调试 int rst = sqlite3_step(stmt); //如果完成 if (rst == SQLITE_DONE) { NSLog(@"删除成功!"); } else { NSLog(@"删除失败!"); } sqlite3_finalize(stmt); }
/** * 更新数据 * * @param humen 需要更新的Humen模型 */ -(void)updateHumenFromSqlite:(Humen *)humen withIndex:(NSInteger)index { //获取当前的对象的ID NSInteger ID = ((Humen *)self.humen[index - 1]).humenId; //数组替换 [self.mHumen replaceObjectAtIndex:index - 1 withObject:humen]; //预编译语句 char * updateSQL = "update t_humen set name=?,age=?,tele=?,address=? where id=?"; sqlite3_stmt * stmt; //准备 sqlite3_prepare_v2(self.humendate, updateSQL, -1, &stmt, NULL); //绑定参数数据 sqlite3_bind_text(stmt, 1, [humen.name UTF8String], -1, NULL); sqlite3_bind_int(stmt, 2, (int)humen.age); sqlite3_bind_text(stmt, 3, [humen.tele UTF8String], -1, NULL); sqlite3_bind_text(stmt, 4, [humen.address UTF8String], -1, NULL); sqlite3_bind_int(stmt, 5, (int)ID); //分部调试 int rst = sqlite3_step(stmt); //如果更新完成 if (rst == SQLITE_DONE) { NSLog(@"更新成功!"); }else { NSLog(@"失败!%d",rst); } sqlite3_finalize(stmt); }
最后一个功能就是查,查的话在这个方案里是不需要再对数据库进行操作的,因为增删改的时候对本地的数组进行了操作,所以本地的数组存的数据就是实时的数据库里存的对象,整个工程只需要在初始化的时候对数据库进行一次加载即可,查询如下
/** * 根据姓名查询名字 * * @param name 查询的名字 */ -(void)selectHumenFromWithName:(NSString *)name { //可变数组存储符合条件的对象 NSMutableArray * mutableHumen = [NSMutableArray array]; //只需在数组中查询即可,不需要在执行数据库 for (Humen * humen in self.mHumen) { if ([humen.name isEqualToString:name]) { //添加到数组 [mutableHumen addObject:humen]; } } //改变当前的数组 self.mHumen = mutableHumen; }
/** * 关闭数据库 */ -(void)closeSqlite_db { sqlite3_close(self->_humendate); }
重写dealloc中的方法,说到dealloc中的方法,在ARC环境下,是不需要写[super dealloc]的,写上也会报错
/** * 消除对象的时候关闭数据库 */ -(void)dealloc { //关闭数据库 [self closeSqlite_db]; }
页面的布局依旧选择了storyboard,简单布局如下,root视图控制器为一个导航控制器,连接着能够显示的cell,后面的页面负责添加以及更新
@interface HumenTableViewController () @property(nonatomic,strong)Sqlite3Manager * sqliteManager; @end
- (void)viewDidLoad { [super viewDidLoad]; //初始化单例 self.sqliteManager = [Sqlite3Manager shareSqlite3Manager]; //添加导航栏的右按钮,回调方法为 toAddViewController self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(toAddViewController)]; //添加导航栏的左按钮,回调方法为 toSearchViewController self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:@selector(toSearchViewController)]; }
//页面将要跳回动画结束时 -(void)viewWillAppear:(BOOL)animated { //重新加载数据库中的所有数据 [self.sqliteManager loadMHumen]; //刷新列表 [self.tableView reloadData]; }
#pragma mark - barButton target action -(void)toAddViewController { //获取storyboard UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]]; //根据storyboard创建控制对象 UIViewController * viewController = [storyboard instantiateViewControllerWithIdentifier:@"AddViewController"]; //跳转界面 [self.navigationController pushViewController:viewController animated:YES]; }
-(void)toSearchViewController { //准备alertController UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"搜索" message:@"请填入搜索的名字" preferredStyle:UIAlertControllerStyleAlert]; //添加文本框 [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { }]; //添加搜索的动作按钮 [alert addAction:[UIAlertAction actionWithTitle:@"搜索" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { //获取搜索的名字 NSString * name = alert.textFields[0].text; //在数据库对象中进行搜索 [self.sqliteManager selectHumenFromWithName:name]; //刷新列表 [self.tableView reloadData]; //跳回 [self dismissViewControllerAnimated:YES completion:nil]; }]]; //添加取消的动作按钮 [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { //跳回 [self dismissViewControllerAnimated:YES completion:nil]; }]]; //跳出 [self presentViewController:alert animated:YES completion:nil]; }
#pragma mark - Table view data source /** * 返回组数,分组的情况下,因为不分组,所以返回1 * * @param tableView 当前的tableView * * @return 组数 */ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } /** * 组的行数 * * @param tableView 当前的tableView * @param section 组的个数 * * @return 返回每部分的行数 */ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.sqliteManager.humen.count; } /** * cell显示的内容 * * @param tableView 当前的tableView * @param indexPath 当前的位置 * * @return 打包好的cell */ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //获取模型 Humen * humen = self.sqliteManager.humen[indexPath.row]; //创建表格cell UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; //简单赋值 cell.textLabel.text = humen.name; return cell; }
/** * 点击行的时候 * * @param tableView 当前的tableView * @param indexPath 当前的位置 */ -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { //获取当前的模型 Humen * humen = self.sqliteManager.humen[indexPath.row]; //获得当前的storyboard UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]]; //获得跳转的ViewController UIViewController * vc = [storyboard instantiateViewControllerWithIdentifier:@"AddViewController"]; //KVC赋值 [vc setValue:humen forKey:@"humen"]; [vc setValue:indexPath forKey:@"index"]; //跳转 [self.navigationController pushViewController:vc animated:YES]; }
/** * 列表视图能够编辑 * * @param tableView 当前的tableView * @param indexPath 当前的位置 * * @return YES表示可以编辑 NO表示不可以编辑 */ - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { return YES; }
/** * 当前的编辑模式进行相应的操作 * * @param tableView 当前的tableView * @param editingStyle 编辑的风格 * @param indexPath 当前的位置 */ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { //从数据库中删除当前的对象 [self.sqliteManager deleteHumenFromSqlite:indexPath.row + 1]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; } else if (editingStyle == UITableViewCellEditingStyleInsert) { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view } }
#import "AddViewController.h" #import "Sqlite3Manager.h" #import "Humen.h" @interface AddViewController () @property (strong, nonatomic) IBOutlet UITextField *nameText; @property (strong, nonatomic) IBOutlet UITextField *ageText; @property (strong, nonatomic) IBOutlet UITextField *teleText; @property (strong, nonatomic) IBOutlet UITextField *addressText; @property (nonatomic,strong) Sqlite3Manager * sqliteManager; //更新时专用 @property(strong,nonatomic)Humen * humen; @property(nonatomic,strong)NSIndexPath * index; @end
- (void)viewDidLoad { [super viewDidLoad]; //实例化单例属性 self.sqliteManager = [Sqlite3Manager shareSqlite3Manager]; //设置导航的右上角按钮 self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(addHumenToSqliteFromAddViewController)]; //表示代表更新视图 if (self.humen) { self.navigationItem.title = @"更新视图"; //赋值 self.nameText.text = self.humen.name; self.ageText.text = [NSString stringWithFormat:@"%ld",self.humen.age]; self.teleText.text = self.humen.tele; self.addressText.text = self.humen.address; } else { self.navigationItem.title = @"添加视图"; } }
-(void)addHumenToSqliteFromAddViewController { //初始化humen实例 Humen * humen = [[Humen alloc]initWithName:self.nameText.text Age:[self.ageText.text intValue] Tele:self.teleText.text Address:self.addressText.text]; //表示更新 if (self.humen) { //更新到数据库 [self.sqliteManager updateHumenFromSqlite:humen withIndex:self.index.row + 1]; } //表示添加 else { //添加到数据库sqlite [self.sqliteManager addHumenToSqlite:humen]; } //调回原页面 [self.navigationController popViewControllerAnimated:YES]; }