高度封装FMDB框架:各用一句代码更新(添加&修改),查询,删除用户信息


简书博客已经暂停更新,想看更多技术博客请到:


在移动开发中,有时不得不在客户端本地保存一些数据。在iOS端,我们可以使用plist,属性列表等技术来存储数据,而相比而下更高端一点的,我们也可以使用数据库来存储数据。

有趣的是,很多iOS开发者没有去选择使用苹果自家的Core Data技术来操作数据库,而是选择了FMDB这个第三方框架。

该框架很好地封装了操作繁琐的SQLite语句,让数据库的操作更加面向对象,而且上手快,门槛低,不用学习数据库的相关知识就可以使用自如。如此优秀流行的框架是值得学习的,于是笔者这两天研究了一下FMDB。研究后,略有所思,将它封装了一下,写了一个Manager类,最后结合了一个Demo演示如何使用这个类。

该博客分为两个部分:第一个部分讲解笔者封装的这个Manager类;第二部分结合Demo来体现该类的实用性。

1. 封装FMDB


1.1 封装类的功能

首先看一下这个类的大名:SJUserInfoManager

  • SJ:笔者的名字缩写,作为前缀,都懂得。
  • UserInfo:说明这个类用于操作用户信息。
  • Manager:这个类只具有工厂方法,省内存,而且方便使用。

这个类的功能是:它可以创建一个关于用户信息的表(数据库),可以保存,修改,读取,删除用户信息

现在几乎每个app都有登录功能,有登录就意味着有用户信息。有的时候,我们需要将一些用户信息存储到本地,方便今后的读取和操作。

而对于用户信息,几乎永远不变的一项就是用户id,因为用户可以改自己的名字,自己的注册手机号,用户签名等等,然而用户id是唯一一成不变的,后端查找用户信息一般都通过用户id来查找,这不难理解。

因此,这个封装类基于用户id(user_id),让使用者可以自主添加一项自定义的用户信息(可以是用户名,用户签名,用户性别等等),从而形成一个只具有两个纵行的表(第一个纵行是默认的字段:user_id,第二个纵行是自定义字段,可以是user_name等等)。

这样一来,我们就可以生成很多基于用户id的表:可以是用户姓名的表,可以是用户出生日期的表,可以是用户手机号的表等等。

1.2 API介绍

该封装类的API一共有五个,分别是:

  1. 创建表格
  2. 更新用户信息(添加&修改)
  3. 查询某个用户的信息
  4. 查询全部用户的信息
  5. 删除某个用户的信息

下面开始一一讲解:

1. 创建表格

/*
 ********** Create table with tableName and fieldName **********
 *
 * @param   dataBaseName    tableNameString (表的名字)
 * @param   userInfoField   fieldNameString(自定义字段名)
 *
 * @return  if the table is successfully created
 *
 */
+ (BOOL)createDataBaseWithName:(NSString *)dataBaseName andUserInfoField:(NSString *)userInfoField;

这个方法的意图很明显,只要传进去表的名字和自定义字段的名字就能创造一个表。

  • 创建成功,返回YES;
  • 创建失败,返回NO。

而且这个表有一个默认的字段:user_id。因为通过这个类创建用户信息的表是基于用户id来操作的,前面已有说明。

2. 更新用户信息(添加&修改)

/*
 ********** update specific userInfo with specific userID and userInfoField and userInfoValue **********
 *
 * @param   dataBaseName    tableNameString (表的名字)
 * @param   userID          userIDString(用户id的值)
 * @param   userInfoField   fieldNameString(自定义字段名)
 * @param   userInfoValue   userInfoValueString(字段对应的值)
 *
 * @return  the result of updating specific userInfo 
 *
 */
+ (NSString *)updateUserInfoIntoDataBase:(NSString *)dataBaseName withUserID:(NSString *)userID andUserInfoField:(NSString *)userInfoField andUserInfoValue:(NSString *)userInfoValue;

这个方法用于更新用户信息,传入表的名字,用户id,自定义字段名,和自定义字段对应的值。

  • 如果输入的表不存在,则返回相应的错误信息。
  • 如果输入的用户id已经存在,就更新对应的用户信息。
  • 如果输入的用户id不存在,就添加这个用户的信息。

3. 查询某个用户的信息

/*
 ********** Query specific userInfoValue with tableName and userID and userInfoField **********
 *
 * @param   dataBaseName    tableNameString (表的名字)
 * @param   userID          userIDString(用户id的值)
 * @param   userInfoField   fieldNameString(自定义字段名)
 *
 * @return  specific userInfoValue (表内某用户id对应的用户信息)
 *
 */
+ (NSString *)queryUserInfoInDataBase:(NSString *)dataBaseName WithUserID:(NSString *)userId andUserInfoField:(NSString *)userInfoField;

该方法用于查询某个用户的信息,传入表的名字,用户id和自定义字段名。

  • 如果输入的表不存在,则返回相应的错误信息。
  • 如果输入的用户id存在,则返回对应的信息。
  • 如果输入的用户id不存在,则返回相应的错误信息。

4. 查询全部用户的信息

/*
 ********** Query all userInfos in this table with userInfoField **********
 *
 * @param   dataBaseName    tableNameString (表的名字)
 * @param   userInfoField   fieldNameString(自定义字段名)
 *
 * @return  all the userInfos in this table (表内所有的用户信息)
 *
 */
+ (NSDictionary *)queryUserInfosInDataBase:(NSString *)dataBaseName andUserInfoField:(NSString *)userInfoField;

该方法用户获取某个表内的所有用户信息,传入表的名字和自定义字段名即可。
返回的字典里包含一个数组,数组元素为表的每一行的信息。每一行的信息是一个字典:

  • 其中一个key为默认的字段名:user_id,它的值为对应的user_id的值。
  • 另一个key为添加的自定义字段名,它对应的值为该字段对应的值。

5. 删除某个用户的信息

/*
 ********** Delete specific userInfo with specific userID **********
 *
 * @param   dataBaseName    tableNameString (表的名字)
 * @param   userId          userIDString(用户id的值)
 *
 * @return  the result of deleting specific userInfo (删除的结果)
 *
 */
+ (NSString *)deleteUserInfoInDataBase:(NSString *)dataBaseName WithUserID:(NSString *)userId;

该方法用于删除表里的某个用户信息,只要传入表的名字和用户id即可,可以删除表中对应的一整行信息。同样地,如果输入的表不存在,则返回相应的错误信息。

如果觉得有点抽象的话,可以看下面这个Demo,可以看到该封装类的具体使用方法。

2. Demo演示


在这个Demo中,我们要在表里添加的自定义字段名(fieldNameString)为:“user_name”。也就是说这个表将保存用户id和用户名信息。

2.1 需求

  1. 在插入板块中插入用户信息(用户id和用户名)。
  2. 在查询板块中,根据输入的用户id,可以显示对应的用户名。如果没有对应的用户id,则显示“没有对应id”。
  3. 在删除板块中,根据输入的用户id,可以删除对应的用户信息(包括用户id和用户名,也就是删除了表的一整行)。如果没有对应的用户id,则显示“没有对应id”。
  4. 点击导航栏右侧的按钮,进入“用户信息列表页”。在这一页显示当前表里的全部用户的信息(在cell的textLabel里显示用户名;在cell的detailTextLabel里显示用户id)。

2.2 效果图

左图:数据库操作页面(插入,查询,删除板块)| 右图:数据库全部用户信息
本地沙盒中sqlite表文件内容

2.3 代码讲解

1. 最先导入这个封装类和FMDB框架:

#import "SJUserInfoManager.h"

2. 因为表的名字和自定义字段是固定的,所以就以宏来定义了:

#define DATABASENAME  @"userInfoTable" //表的名字
#define USERINFOFIELD @"user_name"     //自定义字段的名字

3. 添加几个输入框的属性,获取输入框的内容;和查询结果显示Label:

@property (strong, nonatomic) IBOutlet UITextField *insertUserIdTextfield;       //插入输入框:输入用户id
@property (strong, nonatomic) IBOutlet UITextField *insertUserInfoValueTextfiled;//插入收入框:输入用户名

@property (strong, nonatomic) IBOutlet UITextField *queryUserIdTextfield;        //查询输入框:输入用户id
@property (strong, nonatomic) IBOutlet UILabel *queryUserInfoValueLabel;         //查询结果显示Label:显示用户id对应的用户名

@property (strong, nonatomic) IBOutlet UITextField *deleteUserIdTextField;       //删除输入框:输入用户id

4. 下面看一下封装的增改&查&删的代码:

//插入用户信息
- (IBAction)insertAction:(id)sender {
   
    NSString *result = @"";
    
    if (self.insertUserInfoValueTextfiled.text.length == 0) {
        
         result = @"Please Input UserID!";//没有输入用户id就点击了插入按钮
        
    }else{
        
         result = [SJUserInfoManager updateUserInfoIntoDataBase:DATABASENAME withUserID:self.insertUserIdTextfield.text andUserInfoField:USERINFOFIELD andUserInfoValue:self.insertUserInfoValueTextfiled.text];
    }
   
   [self showAlertWithTitle:result];
    
}

//查询用户信息
- (IBAction)queryUserInfoValue:(UIButton *)sender {
    
    NSString *result = @"";
    
    if (self.queryUserIdTextfield.text.length == 0) {
        
        result = @"Please Input UserID!";//没有输入用户id就点击了查询按钮
        self.queryUserInfoValueLabel.text = @"";//重置查询输入框
        
    }else{
        
        result =  [SJUserInfoManager queryUserInfoInDataBase:DATABASENAME WithUserID:self.queryUserIdTextfield.text andUserInfoField:USERINFOFIELD];
        self.queryUserInfoValueLabel.text = result;
        [self showAlertWithTitle:result];
        
    }
    
    [self showAlertWithTitle:result];
}

//删除用户信息
- (IBAction)deleteUserInfoWithUserID:(UIButton *)sender {
    
    NSString *result = @"";
    
    if (self.deleteUserIdTextField.text.length == 0) {
        
        result = @"Please Input UserID!";
        
    }else{
        
        result =  [SJUserInfoManager deleteUserInfoInDataBase:DATABASENAME WithUserID:self.deleteUserIdTextField.text];
    }
    
    [self showAlertWithTitle:result];
    
}

其实不难看出,除了处理错误信息的代码以外,数据库的操作代码是非常简洁的:都是一行结束,而且返回一个结果字符串或者布尔值。

5. 在进入第二页之前,需要查询表内所有的用户信息并传递给第二个页面的VC:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController isKindOfClass:[DataListTableViewController class]]) {
        if ([segue.identifier isEqualToString:@"userInfosList"]) {
            
            NSDictionary *userInfosDict = [SJUserInfoManager queryUserInfosInDataBase:DATABASENAME andUserInfoField:USERINFOFIELD];
            DataListTableViewController *dataListVc = (DataListTableViewController *)segue.destinationViewController;
            dataListVc.userInfosDict = userInfosDict;
        }
    }    
}

6. 在第二页的viewDidLoad方法里获取用户信息列表,并刷新表格将其显示出来:

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    NSString *alertTitle = [self.userInfosDict objectForKey:@"result"];
    [self showAlertWithTitle:alertTitle];
    
    NSArray *userInfosArray = [self.userInfosDict objectForKey:@"userInfosArray"];
    if ([userInfosArray count] != 0) {
         self.userInfosArray = userInfosArray;
        [self.tableView reloadData];
    }
    
}

想知道Demo是如何实现的么?

Demo传送门:SJUserInfoManager - GitHub

如果可以给星星,或者给笔者提意见,那就再好不过啦~

最后的话


说来惭愧,笔者封装的这个类的功能还是很有局限性的:

  1. 操作表格前必须创建一次表格(一次就可以)。
  2. 只支持NSString类型的值。
  3. 除user_id字段以外只支持一个自定义字段。
  4. 不同的自定义字段必须对应不同的表格名,也就是说不同的自定义字段不能对应同一个表格名。
  5. 数据库操作API的返回值还不够完善,最好以枚举类型返回,有待改进。
  6. 没有使用FMDB的队列API。

虽然这个封装很简单,但是笔者始终赞同学习的最终目的在于应用和创造这句话。如果只是用眼睛看FMDB框架的API或是复制粘贴一些别人写好的FMDB的应用代码,那么其实是意义不大的。

如果在学习后,可以融会贯通,将学到的知识可以按照自己的意图加以改进和运用的话,那么相对于“搬运工”式学习来说,显然收获更大。

这是笔者第一个开源项目,虽然简单,算上优化和改bug只写了大概3个小时,但是毕竟是开源的第一步,对自己的鼓励还是蛮大的,以后还会封装优化更多的库,加油~

本文已同步到个人博客:传送门,欢迎常来^^

本文已在版权印备案,如需转载请访问版权印。48422928

获取授权

-------------------------------- 2018年7月16日更新 --------------------------------

注意注意!!!

笔者在近期开通了个人公众号,主要分享编程,读书笔记,思考类的文章。

  • 编程类文章:包括笔者以前发布的精选技术文章,以及后续发布的技术文章(以原创为主),并且逐渐脱离 iOS 的内容,将侧重点会转移到提高编程能力的方向上。
  • 读书笔记类文章:分享编程类思考类心理类职场类书籍的读书笔记。
  • 思考类文章:分享笔者平时在技术上生活上的思考。

因为公众号每天发布的消息数有限制,所以到目前为止还没有将所有过去的精选文章都发布在公众号上,后续会逐步发布的。

而且因为各大博客平台的各种限制,后面还会在公众号上发布一些短小精干,以小见大的干货文章哦~

扫下方的公众号二维码并点击关注,期待与您的共同成长~

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

推荐阅读更多精彩内容

  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,652评论 0 15
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,398评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 有的人向往美好的事物,有的人向往遥远的地方,有的人向往自由的生活,有的人…… 有的人说出国留学是一个很了不...
    92f37b0a38e5阅读 558评论 0 0
  • 妈,我想你了,如果没记错,我们已经近两个月没见面了。你在老家怎么样呢这几天,过得还开心么,我猜想你一定想念着城市里...
    小沙发阅读 280评论 0 0