公司项目已经存在两年了,版本已经到了三点,但是本地持久化数据存储一直使用的是GVUserDefaults,它扩展了NSUserDefaults第三方库.但是随着业务的发展,需要存储的地方越来越多,GVUserDefaults越来越不能满足需求。当我们受不了的时候,经过一番讨论,我们决定使用FMDB这个封装了SQLite3的第三方库。本文以此为主线,梳理了一些关于数据库和本地化存储的知识,但是这篇文章完全没有提到CoreData。喜欢用CoreData的同学,让我说声抱歉,浪费了你们宝贵的20多岁的时间。这篇文章的逻辑如下图所示:iOS本地化持久化存储方式概述说到iOS本地化存储方式,大家可能并不陌生。NSUserDefault、File、Keychain、DataBase无非就是这几个方法。NSUserDefault、File:这两个使用方法很简单。需要注意的一点是,存储的对象需要遵守和实现NSCoding协议中的两个方法。适用范围也是一些小规模的数据。实际上,NSUserDefault的底层实现仍然保存在一个.plist文件中。Keychain:用于存储一些隐私信息,如密码、证书等,Keychain中存储的信息不会在App删除时丢失,并且在用户重新安装App后仍然有效。这同样适用于应用程序之间的数据共享。DataBase:说到存储,就不得不提到DataBase技术。移动端使用的DBMS一般是SQLite3。iOS下,SQLite3的API是纯C语言。这样一来,我们长期从事面向对象开发的朋友们突然找不到对象了,我们有点慌了。幸运的是,开源社区已经出现了FMDB这样优秀的第三方框架来帮助我们检索对象。同样,Apple也发布了一项名为CoreData的新技术(不过CoreData不是本文的重点)。数据库适合存储大规模的数据,而且比上面的方法更方便查找,所以在存储大量数据的时候,还是需要用到数据库的,这也是我们放弃GVUserDefaults的原因。数据库基础知识数据库首先要有数据Data,然后数据的名称升级为DataBase。这时候就需要一个管理系统来管理数据库,即DataBaseManagerSystem。最后,它成为一个具有DataBaseAdministrator和上述名称的系统。即所谓的DataBaseSystem。Data-->DataBase-->DataBaseManagerSystem-->DataBaseSystemData:数据库存储的基本对象。DataBase:说到数据库,大家有个模糊的概念,不就是一个用来存放数据的大仓库吗?没什么可说的。其实这样理解已经很好了,但是更专业一点的是,数据库就是有组织地存储的数据的集合。DataBaseManagerSystem:数据库管理系统是介于用户和操作系统之间的一层数据管理软件。常见的DBMS包括MySQL、PostgreSQL、MicrosoftSQLServer、Oracle、Sybase和IBMDB2。当然,这些都是服务器端使用的DBMS,而移动端使用的DBMS是SQLite3,这也是本文的重点。DataBaseSystem:将数据库引入计算机系统后的系统,一般由数据库、数据库管理系统、应用系统、数据库管理员(DBA)组成。通常情况下,数据库系统被称为数据库,所以有时我们会感到困惑。当你说DBS时,他会想到DB。等你转成DB,他又开始说DBS了。所以,当你真正想要了解一些知识的时候,基本的概念一定要比较清楚,才不容易搞混。SQL语句SQL(StructuredQueryLanguage),结构化查询语言,一种专门用来与数据库进行通信的语言。既然要操作数据库,就必须会写SQL语句。下面我简单列出几条简单的SQL语句,仅供参考。如果想深入了解SQL语句,请参考其他资料,本文在此不做过多介绍。这里以student表为例写几条简单的SQL语句//创建一张表(table)一个student表表名:student字段id:学号,作为主键,type为integer字段名:学生姓名,类型为字符串,不能为空字段age:学生年龄,类型为整数,可以为空。字段也叫列(column)createtableifnotexistsstudent(idintegerprimarykeyautoincrement,nametextnotnull,ageinteger);//删除学生表droptableifexistsstudent;//插入一条记录,主键id会自动增加并自动赋值,这条记录也叫row(row)inserttostudent(name,age)values('Xiaoming',20);//删除名字为小明的学生,其中关键字where是条件,如果没有这个条件,会影响整个表deletefromstudentwherename='Xiaoming';//更新符合条件的记录updatestudentsetage=21wherename='Xiaoming';//查询符合条件的记录select*fromstudentwherename='Xiaoming';数据库使用如果不用CoreData,那么无论是使用纯C语言的SQLite3库,还是使用封装了它的FMDB,都得设计适合自己业务的表结构。关于表的设计,可以有两种设计模式。数据库表的设计第一种设计方式是将模型中的每个属性作为表的一个字段,这样查询和读取更方便,但是个人感觉这种模式适合的业务是记录数不多。而且字段尽量不要改。创建表后,修改表结构还是比较麻烦的。具体使用请参考以下代码:@interfaceStudent:NSObject@property(nonatomic,copy)NSString*name;@property(nonatomic,assign)NSUIntegerage;@end//数据存放路径NSString*document=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)lastObject];NSString*dbpath=[documentstringByAppendingPathComponent:@"toyun.sqlite"];//链接数据库self.db=[FMDatabasedatabaseWithPath:dbpath];//打开数据库if([self.dbopen]){[self.dbexecuteUpdate:@"createtableifnotexistsstudent(idintegerprimarykeyautoincrement,nametextnotnull,ageintegernotnull)"];}//实例化对象,即要存储的对象NSMutableArray*array=[NSMutableArray数组];for(NSIntegeri=0;i<10;i++){Student*student=[[Studentalloc]init];student.name=[NSStringstringWithFormat:@"小明%ld",i];student.age=arc4random()%20+10;[数组添加对象:学生];}//AddInsertthedatabaseintothetablefor(Student*studentinarray){[self.dbexecuteUpdateWithFormat:@"insertintostudent(name,age)values(%@,%ld)",student.name,student.age];}[自我.db关闭];NSLog(@"dbpath===%@",dbpath);第二种设计方式这种设计方式是将模型作为一个字段,直接将模型转成NSData存储在这个字段中。这里需要指出的是,最重要的是模型必须实现NSCoding协议,但是在实际项目中,我们的字典到模型的转换大多使用第三方库,现在比较流行的三个第三方库字典到模型的转换、Mantle、MJExtension和YYModel,都默认处理这个问题。所以这里稍微注意一下。第二种方式更适合大量记录,对业务关联性不太敏感。而如果有查找排序的需求,可以从模型中挑出一些属性作为附表的一些字段。工具使用,参考下面的代码:@interfaceStudent:NSObject
