iOS离线缓存架构设计方案

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014205965/article/details/78180772

原文发布在个人简书,更多内容欢迎关注笔者简书 ,评论、互相交流请到简书,谢谢!

现在许多主流的App都会做离线缓存功能,比如“今日头条”,“新浪微博”,每次启动项目或者刷新有网络时都是获取网络数据,网络出错时会展示缓存数据提高用户体验。

笔者就结合之前见过的、以及笔者自己做缓存的方式,谈一谈离线缓存的实现方案以及其中的优缺点。“今日头条”,“新浪微博”都是缓存了第一页的数据,笔者这里也是这样。

无demo不文章,笔者已将demo1 demo2 写好,欢迎下载.

缓存数据的方式一般有以下几种:

  • 保存到plist文件
  • 保存到沙盒
  • CoreData
  • 数据库

由于这里缓存相对大量的数据,采用sqllite数据库来实现离线缓存。

通过下面几个问题来讲述离线缓存的过程

  • 怎么设计SQL语句?
  • 缓存什么样的数据到数据库: JSON格式数据 or 模型格式数据?
  • 缓存key的格式:URL+参数的方式
  • 缓存的方案

一、怎么设计SQL语句?

有的朋友在做缓存的时候,会这样设计sql语句

创建表的sql

插入的sql
上面的方式设计sql语句,看上去明显很繁琐,涉及到的字段很多也容易混乱。笔者不会采用这样方式设计sql,而是像下面这种方式去设计sql

创建表的sql

插入的sql

上面的sql语句很明显避免了那么多字段的干扰。不论是以 JSON数据格式还是模型数据格式,笔者会将数据已二进制的方式存入数据库(BLOB是数据库中用来存储二进制文件的字段类型

  • cache_data 是缓存的二进制数据
  • cache_key 是缓存时唯一的key,通过唯一的key就可以获取的对应的缓存数据(后面还会对这个字段进行详细说明)

二、缓存什么样的数据到数据库: JSON格式数据 or 模型格式数据?

有人喜欢缓存模型(model)->转换成二进制数据->存入数据库
但是缓存模型的过程需要模型实现NSCoding协议并进行coder和encoder,如果采用了像YYModel或者MJExtension这样的第三方库,实现coder和encoder还相对方便一些,但是如果是自己实现这个过程还是有些繁琐的过程。

所以,笔者采用JSON格式数据->转换成二进制数据->缓存数据库,在iOS中不必缓存JSON格式的字符串,而是直接缓存字典就可以,因为字典就是符合JSON格式的数据。不论是字典还是模型数据都是先转换成二进制数据,再将二进制数据存入数据库。

三、缓存key的格式:URL+参数的方式

下面来说一下cache_key的格式,笔者这里采用的是网络接口请求的url+请求参数拼接组成一个完整的字符串来作为cache_key。

拼接url

为什么采用URL+参数的方式作为cache_key那?
因为URL+参数可以区分接口的唯一性,因为做网络请求时知道了url和请求参数就知道了要请求哪个接口。
笔者这里只设计了T_CACHE一张表,所有的数据缓存都存放在这一张表里,所以需要一个区分缓存数据的唯一标识,通过这个唯一标识我们就知道要获取的首页数据的缓存、还是其他什么页的缓存。显然URL+参数作为这个唯一标识很合适,采用URL+参数的方式通用性也很强,我们拿到其他项目也适用。因为不论什么项目几乎都是通过URL+参数方式进行接口请求。

Snip20171009_18.png

四、缓存的方案

针对缓存数据的设计方案,各位可以说是各显神通。
有人会针对每一个要进行离线缓存的接口设计一套sql语句和缓存类进行数据的存取,也有人会像下面的设计方式进行数据存取。

Snip20171008_11.png

笔者离线缓存思路如下:

Snip20171008_10.png

缓存思路

为什么会采用上面的缓存方案那?
因为我们在实际项目开发中,有时候在项目最开始我们并不是很清楚要不要做离线缓存功能的。有时候情况会是这样的,项目已经维护了几个版本了,产品经理某一天突然告诉你XXX界面显示不友好,加上离线缓存功能吧;也有可能你之前的项目经过了好几手,里面有之前的开发人员设计的缓存方案,而每种方案又都不一样。这时采用笔者这种方案是在现有项目基础上,以最小的改动实现离线缓存的一种方式。当然,应该还会有更好的方式吧,如果大家有其他好的方式,非常非常欢迎指点交流。

下面对笔者的缓存方案进行详细讲解
首先先说一下网络层的一个小设计点,有的人会像下面的设计方式进行网络层API的请求。

API的请求

有一个APIRequest统一处理所有的网络请求,每个接口的数据通过block或者是delegate等方式返回去。如果是通过这种方案进行的网络请求,那么就可以通过下面的方式进行离线缓存。

Snip20171008_13.png

说明:
这里需要对isCache666这个参数进行一下说明,因为我们并不需要对所有的接口请求做离线缓存,可能是针对某些接口数据做缓存,那此时我们就需要区分哪些接口要做缓存、哪些不需要做缓存。为了实现这个区分,我们手动的添加了一个isCache666这样一个参数,这里为了直观,就传了一个YES,其实传什么数据都可以,因为在下面判断的时候只是判断cacheKey这个字符串中是否包含isCache666这样的子字符串(这里为了防止和后台返回的字段冲突,所以命名一些不容易冲突的名字)

针对上面的这样情况,笔者已经写好了demo1,详细的细节可以下载demo1看一下


笔者采用的网络API请求方案是这样的,每一个API对应于一个XXXAPIRequest类,然后这个XXXAPIRequest提供请求的URL和参数、请求方式、该请求是否需要进行离线缓存等信息。
专题列表API
作者列表API

说明:
所有的 XXXAPIRequest类 需要遵守APIRequestProtocol协议,并且必须实现apiRequestURL和apiRequestParams方法,提供请求需要的url和参数; 默认是POST请求方式,可以重写method方法来修改请求方式,同样默认isCache为NO(不进行离线缓存),如果要设置离线缓存,重写isCache方法,返回YES即可。

针对上述的缓存方案,笔者已经写好了demo2,详细的细节可以下载demo2看一下

最后
上面说的离线缓存方案是笔者个人的一些观点,当然离线缓存方案还有其他的方式,也欢迎大家交流。笔者这里也是抛砖引玉,好的方案欢迎拍过来。

猜你喜欢

转载自blog.csdn.net/u014205965/article/details/78180772