最近几天整了下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
@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
@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];
}