數據持久化方案(若是總結不到位,或者有誤的地方,敬請斧正)sql
1、功能:數據庫
主要是將數據持久化到本地,減小對網絡請求的次數,既節省了用戶的流量,也加強了App的體驗效果。數組
2、種類:緩存
plist存儲:使用XML鍵值對持久化,它適用於少許且數據基本不怎麼改變的狀況。安全
偏好存儲:使用NSUserDefalut持久化,專門用來保存應用程序的配置信息的,通常不要在偏好設置中保存其餘數據。網絡
歸檔序列化存儲:使用二進制序列化持久化,只要遵循了NSCoding協議的對象均可以經過它實現序列化。多線程
沙盒存儲:持久化在Document目錄下,通常持久化一些文件,好比圖片,音頻,視頻等,文件沙盒存儲主要存儲非機密數據。app
本地數據庫存儲:適合儲存大規模數據,管理方便,不過操做稍微複雜一些。框架
3、詳解:函數
一、plist存儲
定義:
plist文件,即屬性列表文件,全名是Property List,這種文件的擴展名爲.plist,所以,一般被叫作plist文件。
做用:
它是一種用來存儲串行化後的對象的文件,在iOS開發中一般用來存儲用戶設置,還能夠用於存儲程序中常常用到而不常常改動的數據。
問題:
(1)什麼數據適合存儲?
能存儲NSString、NSArray、NSDictionary、NSData、NSDate、NSNumber、Boolean不能存儲自定義對象
(2)存到什麼地方?
寫入建立的.plist文件中
(3)使用場景?
plist經常使用於存儲長時間不容易發生變化的數據,例如省市列表、車輛名稱列表之類的數據等,這些數據能夠保存在 plist 文件裏,因此plist適用於存儲小型數據,不推薦用plist作緩衝。
(4)如何使用?
存儲
[dict writeToFile:filePath atomically:YES]; // 字典 [array writeToFile:filePath atomically:YES]; // 數組 [string writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; // 字符串
獲取
NSArray *arr = [NSArray arrayWithContentsOfFile:filePath]; // 數組 NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath]; // 字典 NSString *string = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; // 字符串
(5)有什麼缺點?
由於全部的數據都放在root dictionary裏,每次讀取都要把整個root dictionary取出來再取須要的對象.若是plist文件緩存了幾十M的數據.這樣很費內存和時間。
二、偏好存儲
定義:
User Defaults 顧名思義就是一個用戶爲系統以及程序設置的默認值。
每一個用戶都有本身的一套數據,用戶和用戶之間無法共享的。在蘋果的API中,提供了一個類去存儲用戶的偏好設置。
這個方法推薦只存儲用戶的偏好設置,不要存儲一些字典、數組之類的。
做用:
不少iOS應用都支持偏好設置,好比保存用戶名、密碼、字體大小等設置。
iOS提供了一套標準的解決方案來爲應用加入偏好設置功能,就是每個app都有一個plist文件專門用以保存偏好設置數據。
每一個應用都有個NSUserDefaults實例,經過它來存取偏好設置。
問題:
(1)什麼數據適合存儲?
能夠存儲OC定義的全部數據類型,包括對象(系統和自定義的)類型、基本數據類型,如NSInteger等。
(2)存到什麼地方?
NSUserDefault 本地保存的位置是Library/Preferences 這個目錄下的 plist 文件。
(3)使用場景?
在App中,有時候咱們須要將一些信息進行短時間的保存,方便用戶下次更方便使用App,減小多餘的操做,加強用戶體驗。
好比,保存用戶名、字體大小、是否自動登陸等。
(4)如何使用?
存儲
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults]; [defaults setObject: forKey:];
[defaults setInteger:forKey:];
[defaults setDouble: forKey:];
[defaults setObject: forKey:];
[defaults synchronize];
獲取
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
[defaults objectForKey:];
[defaults objectForKey:];
[defaults integerForKey:];
[defaults doubleForKey:];
(5)注意事項?
三、歸檔序列化存儲
定義:
對象歸檔是iOS中數據持久化的一種方式。 歸檔是指另外一種形式的二進制序列化,但它是任何對象均可以實現的更常規的類型。
做用:
使用對模型對象進行歸檔的技術能夠輕鬆將複雜的對象寫入文件,而後再從中讀取它們。
問題:
(1)什麼數據適合存儲?
要使用對象歸檔,則歸檔的對象所屬類中實現的每一個屬性都是標量,或者都是遵循NSCoding協議和NSCopying協議的某個類的實例對象。
(2)存到什麼地方?
對象歸檔後將獲得一個後綴爲.archive的文件,數據就保存在了這個文件中。
(3)使用場景?
定義某個實例,若是須要持久化該實例從而方便之後使用它的屬性值,同時能夠隨意更改該實例的屬性值,推薦在給實例初始化的同時直接使用歸檔進行存儲。
(4)如何使用?
遵循NSCoding協議
實現NSCopying協議
存儲
NSMutableData *data = [[NSMutableData alloc] init]; //聲明一個二進制流 data,開闢了一個空間 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; //聲明一個歸檔類,把歸檔類的內容放入data中
[archiver encodeObject:id forKey:Key]; //用Key進行編碼 [archiver finishEncoding]; //結束編碼 [data writeToFile:filePath atomically:YES];//編碼結束後,歸檔類的內容已經放入data中了,此時data仍然駐留在內存中,須要寫入文件中
獲取
NSData *data = [[NSMutableData alloc] initWithContentsOfFile:filePath];//用歸檔文件中的數據初始化 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];//聲明一個解歸檔對象,把data中的數據複製給解歸檔對象 id object = [unarchiver decodeObjectForKey:Key]; //用Key進行解碼 [unarchiver finishDecoding]; //結束解碼
(5)有什麼缺點?
當待存儲的實例具備成百上千個屬性的時候,單純的一個個去序列化屬性值耗時又費力。(固然能夠藉助runtime機制解決這個缺點,MJExtension這個框架就是這個原理)
四、Document沙盒存儲
定義:
每一個iOS應用都有本身的應用沙盒(應用沙盒就是文件系統目錄),與其餘文件系統隔離。
應用必須待在本身的沙盒裏,其餘應用不能訪問該沙盒。
沙盒的本質就是一個文件夾,名字是隨機分配的。
目錄:
// 獲取程序的Home目錄 NSString *path = NSHomeDirectory(); // 獲取Document目錄 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) fristObject]; // 獲取Cache目錄 NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) fristObject]; // 獲取Library目錄 NSString *path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) fristObject]; // 獲取Tmp目錄 NSString *path = NSTemporaryDirectory();
做用:
用來存儲和備份稍微較大的不是很重要的數據,好比緩存圖片、音頻、視頻等,最典型的SDWebImage緩存圖片的框架。
固然緩存的時間長短根據開發者選擇持久化的目錄路徑有關。
問題:
(1)什麼數據適合存儲?
圖片、音頻、視頻、文本等
(2)存到什麼地方?
寫入建立的.txt、.data等任意擴展名的文件中
(3)使用場景?
當App中涉及到電子書閱讀、聽音樂、看視頻、刷圖片列表等時,推薦使用沙盒存儲。
由於這能夠極大的節約用戶流量,並且也加強了app的體驗效果。
(4)如何使用?
寫入文件
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) fristObject]; NSArray *array = [[NSArray alloc] initWithObjects:@"內容",@"content",nil]; NSString *filePath = [path stringByAppendingPathComponent:@"testFile.txt"]; [array writeToFile:filePath atomically:YES];
讀取文件
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) fristObject]; NSString *filePath = [path stringByAppendingPathComponent:@"testFile.txt"];
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
五、本地數據庫存儲
定義:
數據庫是一種經常使用的經過表進行數據存儲的方式,表與表之間能夠有一對1、一對多的聯繫,使用外鍵級聯能夠達到多表存取數據的目的。
在iOS中,目前有三種熟知數據庫,分別是Sqlite、CoreData、FMDB,用的比較多的是FMDB+Sqlite結合的方式。
特色:
Sqlite:
CoreData;
FMDB;
做用:
用來進行大數據量的存儲工做,不只僅是容量大,並且經過索引查找速度很快,在App中這個是基本的功能。
問題:
(1)什麼數據適合存儲?
開發者定義的類的實例對象,該對象擁有的屬性能夠是任何類型,例如數字、 字符、 日期、 圖片等等。
(2)存到什麼地方?
寫入建立的.sqlite、.db等任意擴展名的文件中
(3)使用場景?
在App中有大量的數據在沒有網絡的狀況下仍然須要顯示時,此時推薦使用本地數據庫緩存這些數據。
(4)如何使用?
Sqlite:
源碼
NSString *sqlStr = @"INSERT OR REPLACE INTO note (cdate,content) VALUES (?,?)"; sqlite3_stmt *statement; //預處理過程,產生結果集 if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *nsdate = [dateFormatter stringFromDate:model.date]; //綁定參數開始 sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL); sqlite3_bind_text(statement, 2, [model.content UTF8String], -1, NULL); //執行插入 if (sqlite3_step(statement) != SQLITE_DONE) { NSAssert(NO, @"插入數據失敗。"); } } } //清理結果集,防止內存泄露 sqlite3_finalize(statement);
CoreData;
源碼
//獲取實體對象 NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:@「ClassName」 inManagedObjectContext:self.managedObjectContext]; //建立請求對象 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@「ClassName」]; //建立排序對象 NSSortDescriptor *ageSort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:YES] [request setSortDescriptors:@[ageSort]]; //取出全部的數據 NSArray *fetcheObjects = [self.managedObjectContext executeFetchRequest:request error:&error]
FMDB:
self.db = [FMDatabase databaseWithPath:fileName]; //建立數據庫
[self.db open];//打開數據庫
- (FMResultSet *)executeQuery:(NSString*)sql, ... //返回結果集
- (BOOL)next; //遍歷
- { type }ForColumnIndex:(int)columnIdx //取出某一行對應的具體數據
- (BOOL)executeUpdate:(NSString*)sql, ... //執行更新
[self.db close]; //關閉數據庫
源碼
//<1>使用:(須要FMDatabase *db成員變量) //建立或打開:FMDataBase類 self.db = [FMDatabase databaseWithPath:fileName]; [self.db open]; [self.db executeUpdate:@「CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT,age INTEGER)」]; [self.db executeUpdate:@"INSERT INTO t_student(name , age) VALUES(‘admin’,‘10')]; //<2>查詢:FMResultSet類 //1.查詢 FMResultSet *set = [self.db executeQuery:@"SELECT * FROM t_student;"]; //2.取出數據 即 {type}ForColumnIndex: while ([set next]) { //取出姓名 NSString *name = [set stringForColumnIndex:1]; //取出年齡 int age = [set intForColumnIndex:2]; NSString *name = [set stringForColumn:@"name"]; int age = [set intForColumn:@"age"]; NSLog(@"name = %@, age = %d", name, age); } //<3>關閉數據庫 [self.db close];
既然有這五種存儲方案,那麼在項目中應該選擇哪一種是最佳的方式呢,這就涉及到了下面這個問題了。
針對上面的這個問題,基本是能夠有四種參考的維度,分別是:
如今就具體的列表說一下這些區別。
存儲方式
|
數據量
|
數據類型
|
數據載體
|
數據操做特色
|
應用示例
|
---|---|---|---|---|---|
plist存儲 | 適合存儲小數據量並且屬於一類的列表類的數據 | 只能存儲固定的幾種類型,NSString、NSArray、NSDictionary、NSData、NSDate、NSNumber、Boolean,不能存儲自定義對象 | 非自定義實例對象、基本數據 | 直接在可見文件上操做,增刪改查很方便 |
省市列表、表情列表等 |
偏好存儲 | 適合存儲小數據量而是通常是配置信息類的數據,有時根據須要也會存儲一些標誌鍵值數據 | 能夠存儲OC定義的全部數據類型 |
實例對象、基本數據 |
必須依賴NSUserDefaluts實例對象的實例方法進行存取,過程稍微複雜 |
App應用程序的信息配置,如版本號、app名稱、用戶權限等 標誌鍵值,如判斷啓動頁、是否自動登陸等 |
歸檔存儲 | 適合存儲數據量稍微較大的數據 | 只能存儲實現了NSCoding協議和NSCopying協議的實例對象類型。 | 實例對象 | 必須依賴NSKeyedUnarchiver、NSKeyedArchiver的類方法或者實例方法進行存取,有時可能還會結合NSUserDefaluts偏好,過程比較複雜 | 用戶的登陸/註冊信息,如帳號、姓名、年齡、學校、省份等 |
沙盒存儲 | 適合存儲數據量較大的數據 | 都是存儲二進制的NSdata類型 | 文件File | 須要依賴文件管理者NSFileManager將文件寫入指定的沙盒目錄下、從該目錄中再讀取文件,過程更復雜一些 | 圖片、音頻、視頻、文本等,如SDWebImage圖片緩存框架 |
數據庫存儲 | 適合存儲大數據量的數據 | 支持全部的數據類型 | 實例對象 | 增刪改查方便、快捷,能夠任意寫sql語句批量處理數據、數據庫升級簡單等 | App中用戶瀏覽過的數據列表內容、電子書讀書進度等,基本上大多數app都有本地數據庫緩存 |