做爲移動端開發工程師,所須要的數據幾乎所有都是經過網絡獲取,並且網絡請求都有時耗;在網絡好的狀況下這種時耗雖然不足考慮,可是一旦網絡環境很差,會很影響產品體驗。網絡環境沒法控制,可是對於一些數據不常常變更的網絡請求或不必實時更新的數據,咱們能夠選擇將網絡數據緩存本地,適時更新。css
在iOS中涉及存儲方式不外乎這幾種,只是你們各自的分類方式可能有些不一樣。這裏僅是本身的思考與分類。html
瞭解緩存,有必要先了解一下沙盒這個概念。
沙盒其實質就是在iOS系統下,每一個應用在內存中所對應的儲存空間。
每一個iOS應用都有本身的應用沙盒(文件系統目錄),與其餘文件系統隔離,各個沙盒之間相互獨立,並且不能相互訪問(手機沒有越獄的狀況下)。
各個應用程序的沙盒是相互獨立的,在系統內存消耗太高時,系統會收到內存警告並自動將一些退出軟件。這就保證了系統的數據的安全性及系統的穩定性。ios
一個應用的沙盒目錄以下:git
isSubclassOfClass :參數爲類 - 參數類爲其子類或自己 ;程序員
isMemberOfClass :參數爲實例對象 - 參數所屬類爲其自己 ;github
isKindOfClass :參數爲實例對象 - 參數所屬類爲其子類或自己 。sql
SQLite : 它是一款輕型的嵌入式數據庫,安卓和ios開發使用的都是SQLite數據庫;佔用資源很是的低,在嵌入式設備中,可能只須要幾百K的內存就夠了;並且它的處理速度比Mysql、PostgreSQL這兩款著名的數據庫都還快。數據庫
FMDB 正式基於 SQLite 開發的一套開源庫。使用時,須要本身寫一些簡單的SQLite語句。數組
CoreData 是蘋果給出的一套基於 SQLite 的數據存儲方案;並且不須要本身寫任何SQLite語句。該功能依賴於 CoreData.framework 框架,該框架已經很好地將數據庫表和字段封裝成了對象和屬性,表之間的一對多、多對多關係則封裝成了對象之間的包含關係。緩存
Core Data的強大之處就在於這種關係能夠在一個對象更新時,其關聯的對象也會隨着更新,至關於你更新一張表的時候,其關聯的其餘表也會隨着更新。Core Data的另一個特色就是提供了更簡單的性能管理機制,僅提供幾個類就能夠管理整個數據庫。因爲直接使用蘋果提供的CoreData容易出錯,這裏提供一個很好的三方庫 MagicalRecord 。
關於 Core Data 想吐槽的是,數據存儲功能雖然封裝的很好、功能很強大,可是版本迭代中反覆修改數據模型、新增數據模型等問題引發的數據庫遷移問題給開發工做帶來不少沒必要要的工做;尤爲有未解除過該技術的新人加入。
Pod 添加 MagicalRecord 依賴庫以後,文件建立 - 數據實體建立 - 數據遷移 :
新建工程 ,Use Core Data 可選可不選,這就給未勾選該項的舊工程使用 Core Data 技術提供可能
建立 .xcdatamodeld 文件
建立實體、新增屬性
建立實體相應的關聯文件
數據庫遷移步驟 1
數據庫遷移步驟 2
對大多數 APP 而言,都是 Hybrid 開發,Web 頁與原生同時存在,其中 Web 頁多是 UIWeb 也多是 WKWeb 。因此與之相應的緩存系統,應該包括 Web 緩存與 原生接口數據緩存兩部分。
Web 緩存有網絡緩存及 Webkit 框架機制內的緩存。這裏也能夠依據 URL + 時間戳 自行設計一套緩存。
原生接口部分的數據緩存
https://www.jianshu.com/p/ca9d8346e7d6
二。
iOS本地數據持久化的幾種類型
iOS本地數據持久化幾種類型的應用場景及使用
一,iOS本地數據持久化的類型:
1,NSUserDefaults
2,plist
3,Keychain(鑰匙串)
4,歸檔
5,沙盒寫入
6,數據庫
二,應用場景
1,NSUserDefaults
用於存儲用戶的偏好設置和用戶信息,如用戶名,是否自動登陸,字體大小等.
數據自動保存在沙盒的Libarary/Preferences目錄下.
NSUserDefaults將輸入的數據儲存在.plist格式的文件下,這種存儲方式就決定了它的安全性幾乎爲0,因此不建議存儲一些敏感信息如:用戶密碼,token,加密私鑰等!
它能存儲的數據類型爲:NSNumber(NSInteger、float、double),NSString,NSDate,NSArray,NSDictionary,BOOL.
不支持自定義對象的存儲.
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults]; [userDefault setInteger:1 forKey:@"integer"]; [userDefault setBool:YES forKey:@"BOOl"]; [userDefault setFloat:6.5 forKey:@"float"]; [userDefault setObject:@"123" forKey:@"numberString"]; NSString *numberString = [userDefault objectForKey:@"numberString"]; BOOL myBool = [userDefault boolForKey:@"BOOl"]; [userDefault removeObjectForKey:@"float"]; [userDefault synchronize];
須要注意的問題:
NSUserDefaults存儲的數據都是不可變的,想將可變數據存入須要先轉爲不可變才能夠存儲.
NSUserDefaults是定時把緩存中的數據寫入磁盤的,而不是即時寫入,爲了防止在寫完NSUserDefaults後程序退出致使的數據丟失,能夠在寫入數據後使用synchronize強制當即將數據寫入磁盤.
2,plist
即屬性列表文件,全名是Property List,這種文件的擴展名爲.plist,所以,一般被叫作plist文件。它是一種用來存儲串行化後的對象的文件,用於存儲程序中常常用到且數據量小而不常常改動的數據。
能夠存儲的類型:NSNumber,NSString,NSDate,NSData ,NSArray,NSDictionary,BOOL.
不支持自定義對象的存儲.
plist的建立方式有兩種:command + n 建立和純代碼建立,不一樣的建立方式使用方法也天然不一樣
command + n 建立:
建立:(建立方法自行百度)
讀取:
NSString *plistPath = [[NSBundle mainBundle]pathForResource:@"myTest" ofType:@"plist"]; NSMutableDictionary *dataDic = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath]; /**若是爲數組時*/ // NSMutableArray *dataArray = [NSMutableArray arrayWithContentsOfFile:plistPath]; NSLog(@"%@",dataDic);
修改:
[dataDic setObject:@"男" forKey:@"sex"]; [dataDic setObject:@15 forKey:@"age"]; [dataDic writeToFile:plistPath atomically:YES]; NSLog(@"----%@",dataDic);
純代碼建立:
建立:
NSArray *sandBoxPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsPath = [sandBoxPath objectAtIndex:0]; NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"myTestPlist.plist"]; NSLog(@"%@",plistPath);
寫入:
NSMutableDictionary *dic = [NSMutableDictionary dictionary]; [dic setObject:@"18" forKey:@"age"]; [dic setObject:@"胡楊" forKey:@"name"]; [dic writeToFile:plistPath atomically:YES];
讀取:
NSArray *sandBoxPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsPath = [sandBoxPath objectAtIndex:0]; NSString *plistPath = [documentsPath stringByAppendingPathComponent:@"myTestPlist.plist"]; NSLog(@"%@",plistPath); NSMutableDictionary *dataDic = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath]; NSLog(@"-----%@",dataDic);
修改:
與command+n方法相同.
須要注意的問題:
若是須要存儲自定義類型的數據須要先進行序列化!
3,Keychain
用於本地重要數據的存儲,將數據加密後存儲在本地更安全.如:密碼,祕鑰,序列號等.當你刪除APP後Keychain存儲的數據不會刪除,因此在重裝App後,Keychain裏的數據還能使用。從ios 3.0開始,跨程序分享keychain變得可行而NSUserDefaults存儲的數據會隨着APP而刪掉.
使用keychain時蘋果官方已經爲咱們封裝好了文件KeychainItemWrapper,引入便可使用.固然也但是使用其餘優秀的第三方的封裝,好比ssKeychain,使用方法以下:
使用方法
4,歸檔(NSKeyedArchiver)
歸檔是iOS開發中數據存儲經常使用的技巧,歸檔能夠直接將對象儲存成文件,把文件讀取成對象。
相對於plist或者userdefault形式,歸檔能夠存儲的數據類型更加多樣,而且能夠存取自定義對象。對象歸檔的文件是保密的,在磁盤上沒法查看文件中的內容,更加安全。
遵照NSCoding協議,並實現該協議中的兩個方法。若是是繼承,則子類必定要重寫那兩個方法。由於子類在存取的時候,會去子類中去找調用的方法,沒找到那麼它就去父類中找,因此最後保存和讀取的時候新增長的屬性會被忽略。須要先調用父類的方法,先初始化父類的,再初始化子類的。
保存數據的文件的後綴名能夠隨意命名。
demo
5,沙盒寫入
持久化在Document目錄下,通常存儲非機密數據。當App中涉及到電子書閱讀、聽音樂、看視頻、刷圖片列表等時,推薦使用沙盒存儲。由於這能夠極大的節約用戶流量,並且也加強了app的體驗效果.
Application:存放程序源文件,上架前通過數字簽名,上架後不可修改。
Documents: 保存應⽤運行時生成的須要持久化的數據,iTunes同步設備時會備份該目錄。例如,遊戲應用可將遊戲存檔保存在該目錄。
tmp: 保存應⽤運行時所需的臨時數據,使⽤完畢後再將相應的文件從該目錄刪除。應用 沒有運行時,系統也可能會清除該目錄下的文件。iTunes同步設備時不會備份該目錄。
Library/Caches: 保存應用運行時⽣成的須要持久化的數據,iTunes同步設備時不會備份 該目錄。⼀通常存儲體積大、不須要備份的非重要數據,好比網絡數據緩存存儲到Caches下
Library/Preference: 保存應用的全部偏好設置,如iOS的Settings(設置) 應⽤會在該目錄中查找應⽤的設置信息。iTunes同步設備時會備份該目錄。
// 獲取程序的Home目錄 NSString *path = NSHomeDirectory(); // 獲取Document目錄 NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; // 獲取Cache目錄 NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; // 獲取Library目錄 NSString *path = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).firstObject; // 獲取Tmp目錄 NSString *path = NSTemporaryDirectory();
寫入:
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; NSString *filePath = [path stringByAppendingPathComponent:@"test.txt"]; NSLog(@"%@",filePath); NSArray *array = @[@"1",@"2",@"3"]; BOOL isSuccess = [array writeToFile:filePath atomically:YES]; if (isSuccess) { NSLog(@"成功"); } else { NSLog(@"失敗"); }
讀取:
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; NSString *filePath = [path stringByAppendingPathComponent:@"test.txt"]; NSLog(@"%@",filePath); NSArray *tmpArray = [NSArray arrayWithContentsOfFile:filePath]; NSLog(@"%@",tmpArray);
6,數據庫
適合儲存數據量較大的數據,通常使用FMDB和CoreData來實現.
FMDB:
FMDB是iOS平臺的SQLite數據庫框架,FMDB以OC的方式封裝了SQLite的C語言API,使用起來更加面向對象,省去了不少麻煩、冗餘的C語言代碼,對比蘋果自帶的Core Data框架,更加輕量級和靈活,提供了多線程安全的數據庫操做方法,有效地防止數據混亂。
CoreData:
Core Data是iOS5以後纔出現的一個框架,它提供了對象-關係映射(ORM)的功能,即可以將OC對象轉化成數據,保存在SQLite數據庫文件中,也可以將保存在數據庫中的數據還原成OC對象。在此數據操做期間,咱們不須要編寫任何SQL語句.可是直接操做CoreData顯的不是那麼容易,因此我多數的時候會使用MagicRecord來實現.MagicRecord是對CoreData的二次封裝,使用起來簡單操做方便.
FMDB和MagicRecord的性能方面各有千秋,須要根據項目的實際需求進行選擇.沒有最好的方案只有最適合的方案!
數據遷移:
若是使用到數據庫那就不得不提數據遷移的問題,不論是MagicRecord仍是FMDB若是要更新數據庫都要進行數據遷移.
FMDB的數據遷移:
判斷表中有沒有這個字段,若是沒有使用sq語句插入.
/**添加字段/數據遷移*/ - (void)dataMigrationWithTableName:(NSString *)tableName newAdded:(NSString *)newAdded block:(FMDBblock)block { //tableName:表名 //newAdded:新加字段名 [_queue inDatabase:^(FMDatabase * _Nonnull db) { if (![db columnExists:newAdded inTableWithName:tableName]){ NSString *sql = [NSString stringWithFormat:@"ALTER TABLE %@ ADD %@ INTEGER",tableName,newAdded]; BOOL success = [db executeUpdate:sql]; if (success) { block(YES,@"字段添加成功"); } else { block(NO,@"字段添加失敗"); } } }]; }
MagicRecord的數據遷移:
首先在初始化的時候要注意初始化語句.
/**以程序名爲數據庫名,不須要自動升級*/ [MagicalRecord setupCoreDataStack]; /**以程序名爲數據庫名,須要自動升級*/ [MagicalRecord setupAutoMigratingCoreDataStack]; /**自定義數據庫名,不須要自動升級*/ [MagicalRecord setupCoreDataStackWithStoreNamed:@"SQDemo.sqlite"]; /**自定義數據庫名,須要自動升級*/ [MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:@"SQDemo.sqlite"];
next 新建一個模型的新版本
next 添加新字段而且選擇model2爲當前模型
最後爲model2新建實體類就能夠了!
若是有寫的很差的地方歡迎各位指出!
參考:
https://blog.csdn.net/a416863220/article/details/48787723
https://www.jianshu.com/p/cd1a06c7ce09
http://suree.org/2015/09/29/DatabaseThink/