之前项目中使用的是CoraData,发现每次的更新数据库中新的属性会非常的麻烦,这里正好尝试着使用一下 FMDB。写了一个FMDB基本用法(增加、删除、查询)的Demo,修改的代码后续会加上。先贴上github连接地址 Demo地址 ,OSChina连接地址 OSChina连接
看一下实现效果
注意点
- 这篇文章适合初次使用FDMB者,已经掌握了FMDB使用方法的,就不需要看了。
- 在做增删改查的时候 VALUES都是对象,Demo中我为了使用的方便都用了String类型
- 在FMDB这个开源库中,使用到的增、删、改都是更新的动作
- 为了方便操作写一个管理类,主要用来管理数据库创建,数据表的创建查询,这里以学生管理为例。上代码:
先来看一下管理类的.m文件
#import <Foundation/Foundation.h>
@class Student;
@interface StudentManager : NSObject
//因为在很多地方都需要用到,在这里我使用单利设计
+ (StudentManager *)shareManager;
//创建数据库
- (void)createDatabase;
//添加学生,传入的是学生对象
- (void)insertStudent:(Student *)student;
//添加学生,这里传入的是学生的ID
- (void)addStudentWithStudentId:(NSString *)studentId;
//通过学生的ID删除某一个学生
- (void)deleteStudentWithStudentId:(NSString *)studentId;
//根据某个ID查询该学生是否存在
- (NSArray *)findStudentWithId:(NSString *)studentId;
//这个主要是添加学生的时候,判断这个学生是否已经存在
- (BOOL)isStudentExist:(NSString *)studentId;
//查询所有的学生,并返回
- (NSMutableArray *)findAllStudents;
// 删除所有的学生
- (void)clearAllStudents;
@end
- 既然是管理,那就要所有关于数据库的操作在这一个类中完成
下面看一下具体的实现.m文件
#import "StudentManager.h"
#import "Student.h"
#import "FMDB.h"
static NSString *const kStudentDB = @"Students.sqlite";
static NSString *const kStudentTable = @"student";
@interface StudentManager ()
@property (nonatomic, copy) NSString *dbPathName;
@property (nonatomic, strong) FMDatabase *database;
@end
@implementation StudentManager
+ (StudentManager *)shareManager {
static StudentManager *shareManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shareManager = [[StudentManager alloc] init];
});
return shareManager;
}
- (instancetype)init {
self = [super init];
if (self) {
NSInteger status = [self initStudentDBWithDBName:kStudentDB];
if (status == -1) {
//失败
NSLog(@"database name 为空");
}
else {
//创建数据库 或者 已经存在
}
}
return self;
}
//初始化数据库
- (NSInteger)initStudentDBWithDBName:(NSString *)dbName {
if (!dbName) {
NSLog(@"数据库名称为空");
return -1;//初始化数据库失败
}
//将数据库保存在沙盒路径下
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];;
self.dbPathName = [documentPath stringByAppendingFormat:@"/%@", dbName];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isExist = [fileManager fileExistsAtPath:self.dbPathName];
if (!isExist) {
NSLog(@"need create database");
[self connectDB];
return 0;//不存在需要创建
}
else {
NSLog(@"database is exist");
return 1;//已经存在
}
}
//连接数据库
- (void)connectDB {
if (!_database) {
//创建
_database = [[FMDatabase alloc] initWithPath:self.dbPathName];
}
if (![_database open]) {
NSLog(@"打开数据库失败");
}
else {
}
}
//关闭数据库
- (void)closeDB {
BOOL isClose = [_database close];
if (isClose) {
NSLog(@"关闭成功");
}
}
//创建数据库
- (void)createDatabase {
//查找数据库所有的表 并且表的名称为 kStudentDB的数据库
NSString *query = [NSString stringWithFormat:@"select count(*) from sqlite_master where type = 'table' and name = %@", kStudentTable];
FMResultSet *resultSet = [self.database executeQuery:query];
[resultSet next];
NSInteger count = [resultSet intForColumnIndex:0];
//对count进行bool转化
BOOL existTable = !!count;
if (existTable) {
//数据表已经存在 是否更新数据库
NSLog(@"数据库已经存在");
} else {
//插入新的数据库 @"CREATE TABLE IF NOT EXISTS t_student (id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL, age integer NOT NULL);"
NSString *sqlString = @"CREATE TABLE IF NOT EXISTS student (id integer PRIMARY KEY AUTOINCREMENT NOT NULL, student_id text NOT NULL, stu_name VARCHAR(20), stu_score VARCHAR(20))";
BOOL result = [self.database executeUpdate:sqlString];
if (!result) {
NSLog(@"数据表创建失败");
}
else {
NSLog(@"数据表创建成功");
}
}
}
//删除某个学生
- (void)deleteStudentWithStudentId:(NSString *)studentId {
[self.database open];
NSString *sqlQuery = [NSString stringWithFormat:@"DELETE FROM student WHERE student_id=%@", studentId];
BOOL result = [self.database executeUpdate:sqlQuery];
if (result) {
NSLog(@"从数据库删除学生成功!");
}
[self.database close];
}
//插入某个学生
- (void)insertStudent:(Student *)student {
[self.database open];
NSMutableString *sqlQuery = [NSMutableString stringWithFormat:@"INSERT INTO student (student_id, stu_name, stu_score) VALUES(?,?,?)"];
NSString *stuId = [NSString stringWithFormat:@"%@", student.studentId];
NSLog(@"student = %@ %@ %@", student.name, stuId, student.score);
BOOL result = [self.database executeUpdate:sqlQuery withArgumentsInArray:@[stuId,student.name, student.score]];
// BOOL result = [self.database executeUpdate:sqlQuery, student.studentId, student.name, student.score];
if (result) {
NSLog(@"inser student succeed!");
[self.database close];
}
else {
NSLog(@"inser student failure!");
[self.database close];
}
}
//添加某个学生Id
- (void)addStudentWithStudentId:(NSString *)studentId {
[self.database open];
NSMutableString *query = [NSMutableString stringWithFormat:@"INSERT INTO student"];
NSMutableString *keys = [NSMutableString stringWithFormat:@" ("];
NSMutableString *values = [NSMutableString stringWithFormat:@" ( "];
NSMutableArray *arrguments = [NSMutableArray array];
if (studentId) {
[keys appendString:@"student_id,"];
[values appendString:@"?,"];
[arrguments addObject:studentId];
}
[keys appendString:@")"];
[values appendString:@")"];
[query appendFormat:@" %@ VALUES %@", [keys stringByReplacingOccurrencesOfString:@",)" withString:@")"], [values stringByReplacingOccurrencesOfString:@",)" withString:@")"]];
NSLog(@"query = %@", query);
[self.database executeUpdate:query withArgumentsInArray:arrguments];
[self.database close];
}
//清空全部数据
- (void)clearAllStudents {
[self.database open];
NSString *query = @"DELETE FROM student";
BOOL result = [self.database executeUpdate:query];
if (result) {
NSLog(@"删除所有学生成功");
}
else {
NSLog(@"删除所有学生失败");
}
[self.database close];
}
//查询所有的学生
- (NSMutableArray *)findAllStudents {
[self.database open];
NSString *sqlString = @"SELECT student_id, stu_name, stu_score FROM student";
FMResultSet *resultSet = [self.database executeQuery:sqlString];
NSMutableArray *array = [NSMutableArray array];
while ([resultSet next]) {
Student *stu = [Student new];
stu.studentId = [resultSet stringForColumn:@"student_id"];
stu.name = [resultSet stringForColumn:@"stu_name"];
stu.score = [resultSet stringForColumn:@"stu_score"];
[array addObject:stu];
}
[resultSet close];
[self.database close];
return array;
}
//查询某一个学生
- (NSArray *)findStudentWithId:(NSString *)studentId {
[self.database open];
NSString *sqlQuery = [NSString stringWithFormat:@"SELECT student_id FROM student WHERE student_id = %@", studentId];
FMResultSet *resultSet = [self.database executeQuery:sqlQuery];
NSMutableArray *array = [NSMutableArray array];
while ([resultSet next]) {
Student *stu = [Student new];
stu.studentId = [resultSet stringForColumn:@"student_id"];
[array addObject:stu];
}
[resultSet close];
[self.database close];
return array;
}
//判断这个学生是否已经存在
- (BOOL)isStudentExist:(NSString *)studentId {
[self.database open];
if ([self findStudentWithId:studentId].count > 0) {
[self.database close];
return YES;
} else {
[self.database close];
return NO;
}
}
定义好了管理的类,下面就要开始使用了
- 管理的类已经定义好了,使用起来就非常的简单了,一行代码实现增删该查,废话不多说,上代码
#import "StudentListController.h"
#import "Student.h"
#import "StudentManager.h"
#import "StudentInfoCell.h"
typedef NS_ENUM(NSInteger, AlertTextFieldTag) {
AlertTextFieldStudentNameTag = 10,
AlertTextFieldStudentIdTag,
AlertTextFieldStudentScoreTag
};
static NSString *const kStudentInfoCell = @"StudentInfoCell";
@interface StudentListController () {
Student *addStu;//添加的学生
}
@property (nonatomic, strong) NSMutableArray *students;
@property (nonatomic, assign) AlertTextFieldTag textFieldTag;
@end
@implementation StudentListController
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"FMDBTestDemo";
UIBarButtonItem *backItem = [[UIBarButtonItem alloc]
initWithImage:[[UIImage imageNamed:@"back_navigation"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
style:UIBarButtonItemStylePlain
target:self
action:@selector(back:)];
self.navigationItem.leftBarButtonItem = backItem;
UIBarButtonItem *insertItem = [[UIBarButtonItem alloc]
initWithImage:[[UIImage imageNamed:@"mine_profile"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
style:UIBarButtonItemStylePlain
target:self
action:@selector(insertAStudent:)];
self.navigationItem.rightBarButtonItem = insertItem;
//获取所有的学生
self.students = [[StudentManager shareManager] findAllStudents];
//register cell
[self.tableView registerNib:[UINib nibWithNibName:kStudentInfoCell bundle:nil] forCellReuseIdentifier:kStudentInfoCell];
//初始化添加学生的全局变量
addStu = [Student new];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.students.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
StudentInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:kStudentInfoCell];
Student *student = (Student *)self.students[indexPath.row];
[cell configCellWithStudent:student];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
// [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
}
}
#pragma mark - Table view delegate
- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
__weak typeof(self) weakSelf = self;
UITableViewRowAction *deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
NSLog(@"删除数据");
[weakSelf.students removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
Student *student = (Student *)weakSelf.students[indexPath.row];
[[StudentManager shareManager] deleteStudentWithStudentId:student.studentId];
}];
deleteAction.backgroundColor = [UIColor redColor];
UITableViewRowAction *addAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"标记" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
NSLog(@"标记成功");
}];
addAction.backgroundColor = [UIColor orangeColor];
return @[addAction, deleteAction];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80.0;
}
#pragma mark - Button Action
- (void)insertAStudent:(id)sender {
__weak typeof(self) weakSelf = self;
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"手动录入" message:@"请输入学生姓名、学号、考试分数" preferredStyle:UIAlertControllerStyleAlert];
[alertVC addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = @"学生姓名";
textField.tag = AlertTextFieldStudentNameTag;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidchanged:) name:UITextFieldTextDidChangeNotification object:textField];
}];
[alertVC addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = @"学生学号";
textField.tag = AlertTextFieldStudentIdTag;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidchanged:) name:UITextFieldTextDidChangeNotification object:textField];
}];
[alertVC addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = @"学生成绩";
textField.tag = AlertTextFieldStudentScoreTag;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidchanged:) name:UITextFieldTextDidChangeNotification object:textField];
}];
//取消
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
}];
[alertVC addAction:cancelAction];
//确定
UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[[StudentManager shareManager] insertStudent:addStu];
[self.students addObject:addStu];
[weakSelf.tableView reloadData];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
}];
confirmAction.enabled = NO;
[alertVC addAction:confirmAction];
[self presentViewController:alertVC animated:YES completion:nil];
}
- (void)back:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark - Notification
- (void)textDidchanged:(NSNotification *)notification {
UITextField *textField = (UITextField *)notification.object;
NSInteger textFieldTag = textField.tag;
UIAlertController *alertVC = (UIAlertController *)self.presentedViewController;//拿到弹出的Alertcontroller
if (alertVC) {
if (textFieldTag == AlertTextFieldStudentNameTag) {
UITextField *stuNameTextField = [alertVC.textFields objectAtIndex:0];
if (stuNameTextField.text.length > 0) {
addStu.name = stuNameTextField.text;
}
else {
NSLog(@"学生名称为空");
}
} else if (textFieldTag == AlertTextFieldStudentIdTag) {
UITextField *stuIdTextField = [alertVC.textFields objectAtIndex:1];
if (stuIdTextField.text.length > 0) {
addStu.studentId = stuIdTextField.text;
}
else {
NSLog(@"学生名称为空");
}
} else if (textFieldTag == AlertTextFieldStudentScoreTag) {
UITextField *stuScoreTextField = [alertVC.textFields objectAtIndex:2];
if (stuScoreTextField.text.length > 0) {
addStu.score = stuScoreTextField.text;
}
}
else {
NSLog(@"无效的tag");
}
if (addStu.name.length > 0
&& addStu.studentId.length > 0 && addStu.score.length > 0) {
UIAlertAction *confirmAction = alertVC.actions.lastObject;
confirmAction.enabled = YES;
}
}
}