文档章节

理一下iOS本地持久化储存(侧重数据库SQLite)

什么丿情况
 什么丿情况
发布于 2016/03/24 17:02
字数 2712
阅读 10
收藏 0
点赞 1
评论 0

公司的项目存在已有两年,版本也到三点几了,但是本地持久化数据存储,始终用的是GVUserDefaults这个对NSUserDefaults进行了扩展的第三方库。但随着业务的发展,需要存储的地方越来越多,GVUserDefaults也越来也不能适应需求,当我们都忍受不了的时候,经过一番商讨之后,决定使用FMDB这个封装了SQLite3的第三方库。此篇文章以此为主线,理一理数据库和本地化储存的一些知识,但是此篇文章丝毫没有提到CoreData,喜欢使用CoreData的同学,这里先说声对不起了浪费了您20s宝贵的时间。

此篇文章的逻辑如下图所示:


图0-0 此篇文章的逻辑图

iOS本地持久化储存方式概述

说起iOS本地化储存的方式,大家估计在也熟悉不过了,NSUserDefaultFileKeychainDataBase无非也就这几种方式。

  • NSUserDefaultFile:这两种使用方式都很简单,需要注意的一点就是所存储的对象都需要遵守并实现NSCoding协议中的两个方法,适用的范围也都是一些小规模数据,其实NSUserDefault的底层实现还是以.plist文件进行储存的。

  • Keychain:用于储存一些私密信息,比如密码、证书等等,Keychain里保存的信息不会因App被删除而丢失,在用户重新安装App后依然有效。同样也适用于应用之间数据共享。

  • DataBase:说到储存,就不能不提DataBase技术,移动端所用的DBMS一般都是SQLite3,在iOS下,SQLite3API是纯C语言的,这样我们一直以来面向对象开发的朋友们,突然找不到了对象,有点那么的惊慌失措。好在开源社区出现了像FMDB这样优秀的第三方框架帮我们找回了对象,同样苹果自己也出了新的技术就是所谓的CoreData(但CoreData并不是此篇文章介绍的重点)。数据库适合储存大规模数据,而且查找起来也比上述方式方便,所以大量储存的时候,还是要动用数据库,这也是我们放弃GVUserDefaults的原因。

数据库的基本知识

数据库

首先要有数据Data,然后数据多了名字就升级了称为数据库DataBase,这个时候就需要有管理系统去管理数据库也就是DataBaseManagerSystem,最后佐以DataBaseAdministrator及上述名称成为了一个系统就是所谓的DataBaseSystem

Data --> DataBase --> DataBaseManagerSystem --> DataBaseSystem

  • Data: 数据库存储的基本对象。

  • DataBase: 说起来数据库,大家都有一个模模糊糊的概念,不就是一个存放数据的大仓库吗,这还有什么好说的。其实这样理解就已经很好了,但是说的更专业一点就是数据库是一个以某种有组织的方式存储的数据集合。

  • DataBaseManagerSystem: 数据库管理系统是位于用户与操作系统之间的一层数据管理软件。常见的DBMSMySQLPostgreSQLMicrosoft SQL ServerOracleSybaseIBM DB2。当然这些都是用于服务端的DBMS,移动端用的DBMSSQLite3,这也是本文讲述的重点。

  • DataBaseSystem: 在计算机系统中引入数据库后的系统,一般由数据库,数据库管理系统,应用系统,数据库管理成员(DBA)构成。一般情况下称数据库系统为数据库,所以有时候我们就会感到迷糊,你说DBS,他以为DB,你转到DB上了,他又开始讲DBS。所以真正想理解透一些知识的时候,基本概念一定要清晰一些,这样才不容易迷糊。

SQL语句

SQL(Structured Query Language),结构化查询语言,专门用来与数据库通信的语言。既然要操作数据库,SQL语句是必须要会写的。下面我简单列举几条简单的SQL语句仅供参考。想要学习更多的SQL语句的知识,请查阅其他资料,本篇在这儿不过多叙述。

这里以学生表为例写几条简单的SQL语句
// 创表(table)一张学生表 表名:student
   字段id:  学生编号,作为主键,类型为整形
   字段name:学生名字,类型为字符串,并且不能为空值
   字段age: 学生年龄,类型为整形可为空。
   其中字段又称之为列(column)create table if not exists student (    id integer primary key autoincrement, 
    name text not null, 
    age integer);// 删除学生表drop table if exists student;// 插入一条记录,主键id会自增长自动赋值,
   其中记录又称之为行(row)insert into student (name, age) values ('小明', 20);// 删除名字为小明的学生,
   这里的关键字where就是条件,如果无此条件,则影响整张表delete from student where name = '小明';// 更新符合条件的记录update student set age = 21 where name = '小明';// 查询符合条件的记录select * from student where name = '小明';

数据库的使用

如果你没有使用CoreData,那么无论你使用的是纯C语言SQLite3库,还是使用对其进行封装了的FMDB,你都要设计出适合自己业务的表结构。关于表的设计,可以有两种设计模式。

数据库表的设计

第一种设计方式

以模型中的每个属性作为表的一个字段,这样在查询、读取放面操作起来更为方便,但是我个人感觉这种模式适合的业务是记录条数不多。而且字段尽可能的不要更改。创建好表之后,在去修改表结构还是听麻烦的一件事的。具体使用,可参考下面的代码:

@interface Student : NSObject@property (nonatomic, copy) NSString *name;@property (nonatomic, assign) NSUInteger age;@end// 数据储存的路径NSString *document = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];NSString *dbpath = [document stringByAppendingPathComponent:@"toyun.sqlite"];// 链接数据库self.db = [FMDatabase databaseWithPath:dbpath];// 打开数据库if ([self.db open]) {
    [self.db executeUpdate:@"create table if not exists student ( id integer primary key autoincrement, name text not null, age integer not null)"];
}// 实例化对象,即要储存的对象NSMutableArray *array = [NSMutableArray array];for (NSInteger i = 0; i < 10; i++) {
    Student *student = [[Student alloc] init];
    student.name = [NSString stringWithFormat:@"小明%ld", i];
    student.age = arc4random() % 20 + 10;
    [array addObject:student];
}// 将数据库插入表中for (Student *student in array) {
    [self.db executeUpdateWithFormat:@"insert into student (name, age) values (%@, %ld)", student.name, student.age];
}
[self.db close];NSLog(@"dbpath   ===   %@", dbpath);
第二种设计方式

这一种设计模式是将model作为一个字段直接将model转为NSData储在此字段中,在这里要指出的是model必须实现NSCoding协议,不过实际项目中我们字典转模型大都是使用第三方库,而现在比较流行的三个字典转模型的第三方库MantleMJExtensionYYModel都默认对此进行了处理,所以这儿稍微注意一下就好。第二种方法更适合于记录条数比较多,和业务的相关性不是太敏感,而且如果有查找排序这样的需求的话,可以从model挑出某些属性作为表中附带的一些字段。具体使用,参考下面的代码:

@interface Student : NSObject <NSCoding>@property (nonatomic, copy) NSString *name;@property (nonatomic, assign) NSUInteger age;@end@implementation Student- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:_name forKey:@"name"];
    [aCoder encodeInteger:_age forKey:@"age"];
}

- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {    if (self = [super init]) {
        _name = [aDecoder decodeObjectForKey:@"name"];
        _age = [aDecoder decodeIntegerForKey:@"age"];
    }    return self;
}@endNSString *document = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];NSString *dbpath = [document stringByAppendingPathComponent:@"yeemiao.sqlite"];self.db = [FMDatabase databaseWithPath:dbpath];if ([self.db open]) {        
    [self.db executeUpdate:@"create table if not exists student (id integer primary key autoincrement, model blob)"];
}NSMutableArray *array = [NSMutableArray array];    
for (NSInteger i = 0; i < 10; i++) {
    Student *student = [[Student alloc] init];
    student.name = [NSString stringWithFormat:@"小明%ld", i];
    student.age = arc4random() % 20 + 10;
    [array addObject:student];
}// 转为NSData,存入数据库for (Student *student in array) {    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:student];
    [self.db executeUpdateWithFormat:@"insert into student (model) values (%@)", data];
}// 从数据库中查数据FMResultSet *set = [self.db executeQuery:@"select * from student"];NSMutableArray *resultArray = [NSMutableArray array];while (set.next) {    NSData *data = [set objectForColumnName:@"model"];
    Student *student = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    [resultArray addObject:student];
}
[self.db close];

数据库使用中线程安全

在多线程中操作数据库,我们就要考虑线程安全问题,不然就有可能引起数据错乱的问题。解决办法有很多,可以自己去加锁,但是读写速度要求高的话就不太建议加锁了。SQLite3对于多线程是直接支持的,SQLite3库提供了三种方式:single threadmulti threadserialized。同样 FMDB自己也提供了多线程操作数据库的类FMDatabaseQueue,这个使用起来还是比较简单的。

删除缓存

现在大多数的App都是有本地化储存的,但是却不是每个App都对应有删除缓存的功能,起码我们自己的App是没有做删除缓存这个功能的,缓存是为了节省流量,删除缓存是为了节省空间我认为这两个功能同等重要,但是这个需求提了几次,产品不怎么重视啊!特别是在16G的版本下,这个功能还能能提升一些用户体验的。

此功能到也不难实现,搞清楚各种储存方式他们把文件存储到了那个文件夹下面,不同的数据我们储存的地方明显也是不同的,然后根据需求删除对应的数据就OK了,沙盒的具体目录如下所示:

// 沙盒下的文件夹目录Documents: iTunes会同步此文件夹,不应该删除
Library
    Caches: 缓存文件夹,删除缓存主要删除的文件夹
    Preferences: NSUserDefault写入此文件夹下,iTunes会同步,不应该删除
tmp:系统创建的临时文件夹,随时有可能被删除

做清除缓存功能时,可把Library/Caches文件夹下面的文件全部删除,也可以根据业务的需要删除指定的文件夹。

总结

此篇文章还是比较偏重于原理,对于具体的使用则没有说太多,具体使用各种各样,但是基本原理是比较统一的。关于数据库CURD由于我们不是做服务端开发,所以也没有深究,想要研究的话,可在查阅其他资料。除了上述所说的,可能在具体使用中还要考虑数据库版本迁移,数据库同步等需求。这些由于我的水平所限,也没有提到可以参考我写此文时的一篇参考博文iOS应用架构谈 本地持久化方案及动态部署。而NSUserDefaultFile使用方法都很简单也都没有介绍。CoreData太过于重量级,我在项目中也没事实际运用过,这里也没有介绍。


© 著作权归作者所有

共有 人打赏支持
什么丿情况
粉丝 0
博文 14
码字总数 14976
作品 0
青岛
程序员
EFCore2.0@Xamarin.Forms

由于忙于Xamarin的书的创作很久没有和大家见面了,回到博客我会陆续更新一些最新的Xamarin技术,还有最近一直在努力的人工智能相关知识。话说csdn的博客改版了。总觉得变化是好事情啊。 这篇...

dotNET跨平台 ⋅ 05/01 ⋅ 0

安卓应用安全指南 4.5.3 使用 SQLite 高级话题

安卓应用安全指南 4.5.3 使用 SQLite 高级话题 原书:Android Application Secure Design/Secure Coding Guidebook 译者:飞龙 协议:CC BY-NC-SA 4.0 4.5.3.1 在 SQL 语句的断言中使用通配符...

apachecn_飞龙 ⋅ 03/22 ⋅ 0

iOS ZipperDown 漏洞来袭,我们该如何应对?

  昨天傍晚盘古实验室负责任的披露了针对 iOS 应用的 ZipperDown 漏洞,并提供了检索、查询受影响应用的平台: zipperdown.com。基于目前公开的信息,该漏洞的影响面比较大,15000 多个应用...

FreeBuf ⋅ 05/16 ⋅ 0

iOS宇宙大战游戏、调试工具、各种动画、AR相册、相机图片编辑等源码

iOS精选源码 日期时间选择器,swift(http://www.code4app.com/thread-30244-1-1.html) Space Battle 宇宙大战 SpriteKit游戏源码(http://www.code4app.com/thread-30246-1-1.html) LLDebugTo......

sunnyaigd ⋅ 昨天 ⋅ 0

面试官自述:面向高级开发人员的iOS面试问题

当您准备进行技术性iOS面试时,了解您可能会询问哪些主题以及经验丰富的iOS开发人员期望什么是非常重要的。 这是许多硅谷公司用来衡量iOS候选人资历水平的一系列问题。 这些问题涉及iOS开发的...

菇哒微课 ⋅ 04/26 ⋅ 0

一年iOS工作经验,如何一举拿下百度、美团、快手等Offer面经(附面试题)

前言: 先简单说说我最近的面试经历吧。面试的公司很多,大部分最后都能得到令人满意的结果,我将这些体会记录下来,面了这么多公司,如果不留下什么,那岂不是太浪费了。对于我来说,这也是...

原来是泽镜啊 ⋅ 04/24 ⋅ 0

在哪里能查看别人的微信聊天记录

微信是腾讯公司于2011年1月21日推出的一款通过网络快速发送语音短信、视频、图片和文字,支持多人群聊的手机聊天软件。现在朋友之间联系,经常就直接微信语音,方便,而且可以讲地方方言。但...

QQ509990938 ⋅ 05/17 ⋅ 0

2018 一份"有点难"的iOS面试题(5年iOS开发)

序言: 之前一时兴致在本站上出过一份iOS的中级面试题,引起一些关注,不少同学表示对”隐藏关卡“感兴趣。升级版iOS面试题来了,目测难倒90%iOS程序员,目测一大波程序员撸着袖子在靠近。 ...

原来是泽镜啊 ⋅ 05/26 ⋅ 0

【防衰老教程】-windows环境下安装SQLite

什么是 SQLite? SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库一样,您不需要在系统中配置。...

Weijue ⋅ 05/09 ⋅ 0

[OC]-数据缓存(coreData)

Core Data 主要对象 • NSManagedObjectContext :负责应用和数据库之间的交互 (CRUD) ; • NSPersistentStoreCoordinator :添加持久化存储库(如 SQLite 数据 库), 是物理数据存储的物理文件和...

xiaoLoo ⋅ 04/25 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Centos7重置Mysql 8.0.1 root 密码

问题产生背景: 安装完 最新版的 mysql8.0.1后忘记了密码,向重置root密码;找了网上好多资料都不尽相同,根据自己的问题总结如下: 第一步:修改配置文件免密码登录mysql vim /etc/my.cnf 1...

豆花饭烧土豆 ⋅ 今天 ⋅ 0

熊掌号收录比例对于网站原创数据排名的影响[图]

从去年下半年开始,我在写博客了,因为我觉得业余写写博客也还是很不错的,但是从2017年下半年开始,百度已经推出了原创保护功能和熊掌号平台,为此,我也提交了不少以前的老数据,而这些历史...

原创小博客 ⋅ 今天 ⋅ 0

LVM讲解、磁盘故障小案例

LVM LVM就是动态卷管理,可以将多个硬盘和硬盘分区做成一个逻辑卷,并把这个逻辑卷作为一个整体来统一管理,动态对分区进行扩缩空间大小,安全快捷方便管理。 1.新建分区,更改类型为8e 即L...

蛋黄Yolks ⋅ 今天 ⋅ 0

Hadoop Yarn调度器的选择和使用

一、引言 Yarn在Hadoop的生态系统中担任了资源管理和任务调度的角色。在讨论其构造器之前先简单了解一下Yarn的架构。 上图是Yarn的基本架构,其中ResourceManager是整个架构的核心组件,它负...

p柯西 ⋅ 今天 ⋅ 0

uWSGI + Django @ Ubuntu

创建 Django App Project 创建后, 可以看到路径下有一个wsgi.py的问题 uWSGI运行 直接命令行运行 利用如下命令, 可直接访问 uwsgi --http :8080 --wsgi-file dj/wsgi.py 配置文件 & 运行 [u...

袁祾 ⋅ 今天 ⋅ 0

JVM堆的理解

在JVM中,我们经常提到的就是堆了,堆确实很重要,其实,除了堆之外,还有几个重要的模块,看下图: 大 多数情况下,我们并不需要关心JVM的底层,但是如果了解它的话,对于我们系统调优是非常...

不羁之后 ⋅ 昨天 ⋅ 0

推荐:并发情况下:Java HashMap 形成死循环的原因

在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环。这个事情我4、5年前也经历...

码代码的小司机 ⋅ 昨天 ⋅ 2

聊聊spring cloud gateway的RetryGatewayFilter

序 本文主要研究一下spring cloud gateway的RetryGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/G......

go4it ⋅ 昨天 ⋅ 0

创建新用户和授予MySQL中的权限教程

导读 MySQL是一个开源数据库管理软件,可帮助用户存储,组织和以后检索数据。 它有多种选项来授予特定用户在表和数据库中的细微的权限 - 本教程将简要介绍一些选项。 如何创建新用户 在MySQL...

问题终结者 ⋅ 昨天 ⋅ 0

android -------- 颜色的半透明效果配置

最近有朋友问我 Android 背景颜色的半透明效果配置,我网上看资料,总结了一下, 开发中也是常常遇到的,所以来写篇博客 常用的颜色值格式有: RGB ARGB RRGGBB AARRGGBB 这4种 透明度 透明度...

切切歆语 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部