天天看點

iOS資料存儲的四種方案對比

你是用什麼方法來持久儲存資料的?這是在幾乎每一次關于iOS技術的交流或讨論都會被提到的問題,而且大家對這個問題的熱情持續高漲。本文主要從概念上把“資料存儲”這個問題進行剖析,并且結合各自特點和适用場景給大家提供一個選擇的思路,并不詳細介紹某一種方式的技術細節。

談到資料儲存,首先要明确區分兩個概念,資料結構和儲存方式。所謂資料結構就是資料存在的形式。除了基本的NSDictionary、NSArray和NSSet這些對象,還有更複雜的如:關系模型、對象圖和屬性清單多種結構。而存儲方式則簡單的分為兩種:記憶體與閃存。記憶體存儲是臨時的,運作時有效的,但效率高,而閃存則是一種持久化存儲,但産生I/O消耗,效率相對低。把記憶體資料轉移到閃存中進行持久化的操作稱成為歸檔。

二者結合起來才是完整的資料存儲方案,我們最常談起的那些:SQLite、CoreData、NSUserDefaults等都是資料存儲方案。當然在這些架構提供的方案之外,我們自己也可以按照個性化需求訂制方案。這些存儲方案側重不同,支援的形式和方式也各不相同,在不同的使用場景下表現也是各有優劣。但萬變不離其宗,無論什麼方案都可以用下圖來解釋。

iOS資料存儲的四種方案對比

圖1,存儲方案示意圖

以下将對四種存儲方式進行詳細的介紹:

  • NSUserDefaults,用于存儲配置資訊
  • SQLite,用于存儲查詢需求較多的資料
  • CoreData,用于規劃應用中的對象
  • 使用基本對象類型定制的個性化緩存方案

用NSUserDefaults存儲配置資訊

NSUserDefaults被設計用來儲存設備和應用的配置資訊,它通過一個工廠方法傳回預設的、也是最常用到的執行個體對象。這個對象中儲存了系統中使用者的配置資訊,開發者可以通過這個執行個體對象對這些已有的資訊進行修改,也可以按照自己的需求建立新的配置項。

iOS資料存儲的四種方案對比

圖2,筆者手機中[NSUserDefaults standardUserDefaults]内容

NSUserDefaults把配置資訊以字典的形式組織起來,支援字典的項包括:字元串或者是數組,除此之外還支援數字等基本格式。一句話概括就是:基礎類型的小資料的字典。操作方法幾乎與NSDictionary的操作方法無異,另外還可以通過指定傳回類型的方法擷取到指定類型的傳回值。

iOS資料存儲的四種方案對比

圖3,NSUserDefaults提供的指定傳回類型的方法清單

NSUserDefaults的所有資料都放在記憶體裡,是以操作速度很快,并還提供一個歸檔方法:+ (void)synchronize。開發者自定義的配置項(如圖2中的最後一項 key:alkdjfkladsjfmm)會以plist格式的檔案歸檔在相應應用目錄的/Library/Preferences/[App_Bundle_Identifier].plist檔案。再次初始化獲得執行個體對象後,架構會把使用者自定義的這個配置和系統配置合并得到完整資料。

用SQLite存儲查詢需求較多的資料

iOS的SDK裡預置了SQLite的庫,開發者可以自建SQLite資料庫。SQLite每次寫入資料都會産生IO消耗,把資料歸檔到相應的檔案。

SQLite擅長處理的資料類型其實與NSUserDefaults差不多,也是基礎類型的小資料,隻是從組織形式上不同。開發者可以以關系型資料庫的方式組織資料,使用SQL DML來管理資料。 一般來說應用中的格式化的文本類資料可以存放在資料庫中,尤其是類似聊天記錄、Timeline等這些具有條件查詢和排序需求的資料。

每一個資料庫的句柄都會在記憶體中都會被配置設定一段緩存,用于提高查詢效率。另一個方面,由于查詢緩存,當産生大量句柄或資料量較大時,會出現緩存過大,造成記憶體浪費。

SQLite的使用起來要比NSUserDefaults複雜的多,是以建議開發者使用SQLite要搭配一個操作控件使用,可以簡化操作。筆者開發的SQLight是一款對SQLite操作的封裝,把相對複雜的SQLite指令封裝成對象和方法,可以供大家參考。大家可以在Github上擷取這個工程的代碼進一步了解。

用CoreData規劃應用中對象

官方給出的定義是,一個支援持久化的,對象圖和生命周期的自動化管理方案。嚴格意義上說CoreData是一個管理方案,他的持久化可以通過SQLite、XML或二進制檔案儲存。如官方定義所說,CoreData的作用遠遠不止儲存資料這麼簡單,它可以把整個應用中的對象模組化并進行自動化的管理。

iOS資料存儲的四種方案對比

圖4,官方文檔中解釋CoreData給出的對象圖示例

正如上圖所示,MyDocument是一個對象執行個體,有兩個Collection:Employee和Department,存放各自的對象清單。MyDocument、Employee和Department三個對象以及他們之間的關系都通過CoreData模組化,并可以通過save方法進行持久化。

從歸檔檔案還原模型時CoreData并不是一次性把整個模型中的所有資料都載入記憶體,而是根據運作時狀态,把被調用到的對象執行個體載入記憶體。架構會自動控制這個過程,進而達到控制記憶體消耗,避免浪費。

無論從設計原理還是使用方法上看,CoreData都比較複雜。是以,如果僅僅是考慮緩存資料這個需求,CoreData絕對不是一個優選方案。CoreData的使用場景在于:整個應用使用CoreData規劃,把應用内的資料通過CoreData模組化,完全基于CoreData架構應用。

蘋果官方給出的一個示例代碼,結構相對簡單,可以幫助大家入門CoreData。

使用基本對象類型定制的個性化緩存方案

之前提到的NSUserDefaults和SQLite适合存儲基礎類型的小資料,而CoreData則不适合存儲單一的資料,那麼對于類似圖檔這種較大的資料要用什麼方式儲存呢?我給出的建議就是:自己實作一套存儲方案。說到訂制存儲方案大家非常容易質疑,這是不是又在重新發明輪子。我可以非常明确的告訴大家,這絕不是在重新發明輪子。首先要明确,這個所謂的定制方案适用于網際網路應用中對遠端資料的緩存,幾個限制條件缺一不可。

從需求出發分析緩存資料有哪些要求:按Key查找,快速讀取,寫入不影響正常操作,不浪費記憶體,支援歸檔。這些都是基本需求,那麼再進一步或許還需要固定緩存項數量,支援隊列緩存,緩存過期等。從這些需求入手設計一個緩存方案并不十分複雜,Kache是筆者根據開發應用的需求開發的一套緩存元件,通過分析Kache希望可以給大家一個思路。

iOS資料存儲的四種方案對比

圖5,Kache架構圖

如上圖所示,Kache扮演的是一個典型緩存角色。應用加載遠端資料生成應用資料對象的同時,通過Kache把資料緩存起來,再次請求則直接通過Kache擷取資料。

緩存對象可以是NSDictionary、NSArray、NSSet或NSData這些可直接歸檔的類型,每個緩存對象對應一個Key。緩存對象包括資料和過期時間,記憶體中存放在一個單例字典中,閃存中每個對象存為一個檔案。Key空間按照各種順序存放緩存對象的Key集合,Pool為固定大小的數組,當數量達到上限,最早過期的一個Key将被删除,對應的緩存對象也被清除。Queue也是固定大小的數組,以先進先出的規則管理Key的增删。 每一次有新的緩存對象存入,自動檢測Key空間中過期的集合并清除。

此外,控件提供save和load方法支援持久化和重新載入。

Kache最初設計為存放圖檔緩存,之後也曾用于緩存文本資料,由于使用了過期和歸檔相結合的邏輯,可以保證大部分命中的緩存對象都在記憶體中,進而擷取了較高的效率。讀者可以從Github上擷取Kache源碼了解更多。

以上介紹了幾種iOS開發中經常會遇到的儲存資料方法,從其存儲原理、使用方式和适用場景幾方面進行進了簡單的對比。事實上每一款應用都很難采用一種單一的方案完成整個應用的資料儲存任務,需要根據不同的資料類型,選擇最合适的方案,以便整個應用獲得良好的運作時性能。

原文位址:http://www.weste.net/2013/3-29/90016.html

繼續閱讀