iOS FMDB框架 数据库使用

之前项目中使用的是CoraData,发现每次的更新数据库中新的属性会非常的麻烦,这里正好尝试着使用一下 FMDB。写了一个FMDB基本用法(增加、删除、查询)的Demo,修改的代码后续会加上。先贴上github连接地址 Demo地址 ,OSChina连接地址 OSChina连接

看一下实现效果
1111.gif
注意点
  • 这篇文章适合初次使用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;
        }
    }
}

FMDB库的基本使用到这里就结束了。如有使用不正确的地方,请指正🙏。再次附上Demo代码
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,361评论 25 707
  • 走进公园,我眼里就只看见花了,幸好今天一个人独自赏花,不管跟花缠绵多久也没人管我,真是自在惬意! 不常见这种花吧?...
    黯黯红尘一路相伴阅读 497评论 9 9
  • 不知道你们是否有过这样的感觉,下雨天的时候,我们更多愁善感一些,也更容易倦怠一些。想什么都不做,就那样,静静的坐在...
    溱心阅读 287评论 0 0
  • 源起 既然使用RN,跨平台必不可少,iOS 和 Android 在NavigationBar 和TabBar 方面...
    這Er阅读 2,255评论 3 9
  • 意识到相较于社交,更爱在苹果树下独处沉思,大多数乏味的无效社交,并不能使自己愉悦。这很好,那我究竟是为什么热衷在...
    斐狐阅读 225评论 0 2