1. 程式人生 > >iOS離線快取架構設計方案

iOS離線快取架構設計方案

原文釋出在個人簡書,更多內容歡迎關注筆者簡書 ,評論、互相交流請到簡書,謝謝!

現在許多主流的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看一下

最後
上面說的離線快取方案是筆者個人的一些觀點,當然離線快取方案還有其他的方式,也歡迎大家交流。筆者這裡也是拋磚引玉,好的方案歡迎拍過來。