手機 APP 持久化儲存的方案整理

https://www.youtube.com/watch?v=ICSmvT1Wk8A&list=PLzKtnppOmiXAlARyp-aRjP0e-RsWiS4UW&index=48




Preference (偏好設定) 可以視為是一種 iOS 已經封裝好,方便開發者使用的 key-value 小型資料庫,少量資料時使用 Preference (偏好設定) 的效能會優於 SQL 資料庫,反之,大量資料就應該使用 SQL 資料庫。

Preference 會由 iOS 自動轉換為 Plist 進行持久化儲存,所以 Preference 與 Plist 兩者之間沒有效能差異的問題。

但是 Preference (偏好設定) 是自動存放於 Library/Preference,會被 iTunes 自動備份的,所以不可以拿來存放那些不應該被 iTunes 同步的資料,如果濫用會導致無法上架。

Plist 檔案 和 archiving (封存) 都是一次讀取整個檔案到記憶體中,所以如果需要持久化儲存的資料龐大到一定程度時,則應該使用 SQL 資料庫。

Q. Plist 檔案提取 UserDefaults 時會拉回整個 Array 再尋找相關 key 值,那麼 分開儲存 或 合併儲存在同一個 Array,那種方式效率較高? 

網友實測結果是合併儲存在同一個 Array 較高。

=> 不過,原本就不應該使用 Plist 檔案儲存龐大資料的。分開存的優點是不用一次讀取所有資料到記憶體,所以應該仍是端視實際場景的需求做規劃。

plist vs sqlite 性能問題:

PList 是一種文件格式,用於存儲少量結構數據(小於數百KB),通常是字典。儘管可以輕鬆編寫代碼對 PList 進行排序,但 PList 本身並不具有排序功能。

SQLite 是一個完善的數據庫。文件大小(在 iPhone 上)基本上是無限的。內置排序功能。可以進行查詢和關係表設計。性能應與您可能想到的任何排序算法一樣好。
另一方面,sqlite 數據庫將只加載你請求的數據。我不確定您的數據是如何構建的,但您可以很容易地使用單個數據庫表創建鍵值對。 (一鍵列和值列的一個表)。然後,也可以寫一個 Objective-C 類來包裝數據庫查詢,以便能夠寫簡單的語句,如:

NSString *welcomeText = [[MyData sharedData] dataWithKey:@"WelcomeText"]; 

獲取將數據放入數據庫中並不一定非常困難,可以使用命令行 sqlite3 實用程序來批量加載數據。有一個名爲 .import 的命令將從文本文件中導入數據。

另外,有非常多理由不建議使用 coreData 資料庫。

使用 Plist、xml 等「非 SQL 解決方案」和 SQL(無論是原始數據還是作為 Core Data 中的持久性選項之一)之間的區別在於,「非 SQL 解決方案」會將整個持久化文檔加載到記憶體中,而 SQL 僅會加載當前所需的內容。

如果是少量的資料,由於 Plist 等「非 SQL 解決方案」是一次性加載所有資料到記憶體,這時候非 SQL 解決方案的效能會比 SQL 好;反之,大量資料則是選擇 SQL 方案。 




iOS 資料儲存的方法
https://codertw.com/ios/326714/
https://www.itread01.com/p/383654.html
https://www.itread01.com/p/366949.htm
http://www.iotec.tw/?paged=2&cat=12

沙盒機制的議題談的是存在哪裡?不同位置的特性不同

Bundle 和沙盒 (sandbox) 之間的區別:
Bundle:應用程式在手機中的安裝路徑。
sandbox:專門來儲存當前 APP 自己的資料的路徑。

沙盒機制:在 iOS 中每個 APP 都擁有自己的沙盒,APP 只能訪問對應沙盒中儲存的資料,iOS 是不允許跨越沙盒去訪問資料的,所有的資料都是儲存在該沙盒的三個子目錄下:
Document
Library (Library/Caches, Library/Preference)
temp

Document:一般在該目錄下儲存一些比較重要的資料,比如遊戲相關的資料,當連線 iTunes後會自動同步資料。

必須注意,如果將資料資源儲存到該目錄,上架可能會被拒絕 (解決方案是直接設定該資料夾不被 iTunes 備份),總之,不能儲存從網上下載的資料,否則不能上架。

Library:儲存應用設定或者狀態資訊等,在該目錄下還有兩個子目錄:Caches 和 Preference

Library/Caches 存放快取檔案,iTunes 不會備份,因此檔案不會因 APP 退出而刪除 (一般使用SDWebImage 的快取資源都是儲存到這兒)

Library/Preference 儲存應用的所有偏好設定,iOS 的 Setting (設定) 會在該目錄查詢該應用的設定資訊,iTunes會同步資料。

temp:臨時檔案,iTunes不會備份該資料夾中的資料,這個資料夾中的資料,會因為應用的關閉而刪除。

============================================
  • Preference (偏好設定)
iOS開發中也會用到 (Preference) 偏好設定來儲存資料,比如儲存使用者的使用者名稱、密碼、字型大小等設定。通過 NSUserDefaults 來存取偏好設定。

用來儲存應用程式設定和屬性、使用者儲存的資料,使用者再次開啟程式或開機後這些資料仍然存在。

NSUserDefaults 可以儲存的資料型別包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。如果要儲存其他型別,則需要轉換為前面的型別,才能用NSUserDefaults儲存。
    • Plist (屬性列表) 檔案
    Plist 檔案的全名是 Property List (屬性列表) 檔案,屬性列表檔案的副檔名為 .plist,因此通常被稱為 plist 檔案。檔案是 xml 格式的。

    plist 檔案能儲存字典和陣列,不能儲存物件。
    • 資料歸檔/解檔 (序列化/反序列化) (NSKeyedArchiver)
    NSKeyedArchiver 是一種輕量級儲存的持久化方案,資料化歸檔時經過二進位制處理的,所以安全性會比 plist 檔案明碼儲存稍微好一些些。

    (無論是何種儲存方式,安全性最終都取決於資料是否加密後再持久化,而加密方式又有多種方案,比如說對稱金鑰、非對稱金鑰等等)

    資料歸檔可以儲存一些複雜的物件,資料儲存前會經過二進位制處理。

    採用歸檔的形式來儲存資料,該資料物件需要遵守 NSCoding 協議,並且該物件對應的類必須提供 encodeWithCoder 和 initWithCoder 方法。前一個方法告訴系統怎麼對物件進行編碼,而後一個方法則是告訴系統怎麼對物件進行解碼。

    以歸檔的形式儲存資料,只能一次性歸檔儲存以及一次性解壓,所以只能用於少量資料,即便只想改動資料的某一部分,就需要解壓整個資料,再歸檔整個資料。
    • coreData
    coreData 是蘋果官方在 iOS5 之後推出的綜合性資料庫,其使用了物件關係對映技術,將物件轉換成資料,將資料儲存在本地的資料庫中。

    coreData為了提高效率,需要將資料儲存在不同的資料庫中,比如在使用的時候,最好是將本地的資料儲存到記憶體中,這樣的目的是訪問速度比較快。

    蘋果內建框架,和 Xcode 深度結合,可以很方便進行 ORM;但其上手學習成本較高,不容易掌握。穩定性也堪憂,很容易 crash;多線程的支持也比較雞肋。
    • SQLite
    注意:寫入資料庫,字串可以採用 char 方式,而從資料庫中取出 char 型別,當 char 型別有表示中文字元時,會出現亂碼。這是因為資料庫預設使用 ascII 編碼方式。所以要想正確從資料庫中取出中文,需要用 NSString 來接收從資料庫取出的字串。

    直接使用 SQLite 資料庫的缺點包括了它沒有提供資料庫的建立方式;它的底層是基於 C 語言框架設計的,沒有面向物件的 API,用起來非常麻煩;複雜的資料模型的資料建表,非常麻煩。

    在實際開發中,往往都是使用第三方開源、基於 SQLite 封裝的面向物件的框架。

    在 iOS 裡操作 SQLite:
    https://dotblogs.com.tw/toysboy21/2014/04/21/144813



    Android 資料儲存的方法
    https://codertw.com/android-%E9%96%8B%E7%99%BC/335701/
    • SharePreference
    適用於儲存一些鍵值對。無法進行條件查詢。只能儲存 boolean, int, float, long, string 五種資料型別。
    儲存少量的資料,且這些資料的格式非常簡單:字串型、基本型別的值。比如應用程式的各種配置資訊,是否開啟音效、是否使用震動效果、小遊戲的玩家積分等
    • 檔案儲存
    適用於儲存一些簡單的文字資料或者二進位制資料。
    可以在裝置本身的儲存裝置或者外接的儲存裝置中建立用於儲存資料的檔案。
    在預設的狀態下,檔案不能在不同的程式間共享。
    • SQLite
    SQLite Database 資料庫。Android 對資料庫的支援很好,它本身整合了 SQLite 資料庫,每個應用都可以方便的使用它,或者更確切的說,Android 完全依賴於 SQLite 資料庫,它所有的系統資料和結構化資料都儲存在資料庫中。 它具有以下優點:a. 效率出眾,這是無可否認的; b. 十分適合儲存結構化資料;c. 方便在不同的 Activity,甚至不同的應用之間傳遞資料。
    • Content Provider
    Android 系統中能實現所有應用程式共享的一種資料儲存方式,由於資料通常在各應用間的是互相私密的,所以此儲存方式較少使用,但又是必不可少的一種儲存方式。
    例如音訊,視訊,圖片和通訊錄,一般都採用此種方式進行儲存。
    每個 ContentProvider 都會對外提供一個公共的 URI(包裝成 Uri 物件),如果應用程式有資料需要共享時,就需要使用 ContentProvider 為這些資料定義一個 URI,然後其他的應用程式就通過 Content Provider 傳入這個 URI 來對資料進行操作。



    SQLite 是遵守 ACID 的關聯式資料庫管理系統,它包含在一個相對小的 C 程式庫中。與許多其它資料庫管理系統不同,SQLite 不是一個客戶端/伺服器結構的資料庫引擎,而是被整合在用戶程式中。

    SQLite 遵守 ACID,實現了大多數 SQL 標準。作為嵌入式資料庫,是應用程式,如網頁瀏覽器,在本地/客戶端儲存資料的常見選擇。

    它可能是最廣泛部署的資料庫引擎,因為它正在被一些流行的瀏覽器、作業系統、嵌入式系統所使用。同時,它有許多程式設計語言的語言繫結。

    直接使用 SQLite 資料庫的缺點包括了它沒有提供資料庫的建立方式;它的底層是基於 C 語言框架設計的,沒有面向物件的 API,用起來非常麻煩;複雜的資料模型的資料建表,非常麻煩。

    在實際開發中,往往都是使用第三方開源、基於 SQLite 封裝的面向物件的框架。

    Wiki SQLite
    https://en.wikipedia.org/wiki/SQLite

    IOS DB 技術 框架比較
    https://www.twblogs.net/a/5d7dcd1fbd9eee541c3449db

    綜合來說,比較優先考慮的框架是 SQLite.swift 或 WCDB.swift


    SQLite 的優點
    SQLite 是輕量級的,沒有客戶端和服務器端之分,並且是跨平臺的關係型數據庫。
    SQLite 是一個單文件,可以 copy 出來在其他地方用。
    有一個 SQLite.swift 框架非常好用。

    SQLite 的缺點
    SQLite 在併發的讀寫方面性能不是很好,數據庫有時候可能會被某個讀寫操作獨佔,可能會導致其他的讀寫操作被阻塞或者出錯。
    不支持 SQL92 標準,有時候語法不嚴格也可以通過,會養成不好習慣,導致不會維護。
    需要寫很多 SQL 拼接語句,寫很多膠水代碼,容易通過 SQL 注入惡意代碼。
    效率很低:SQL 基於字符串,命令行愛好者甚喜之。但對於基於現代 IDE 的移動開發者,卻是一大痛。字符串得不到任何編譯器的檢查,業務開發往往心中一團熱火,奮筆疾書下幾百行代碼,滿心歡喜點下 Run 後才發現:出錯了!靜心下來逐步看 log、斷點後才發現,噢,SELECT 敲成 SLEECT 了。改正,再等待編譯完成,此時已過去十幾分鐘。

    SQLite3
    獨立程式用來查詢和管理 SQLite 資料庫檔案。SQLite 的使用者可以把這個程式當作如何寫 SQLite 應用程式的範例。

    SQLite3 直接使用比較麻煩,如果使用 Swift 版本推薦使用 SQLite.swift,這是很好的框架,比使用 FMDB 簡單,代碼簡潔很多。SQLite.swift 對 SQLite 進行了全面的封裝,擁有全面的純swift 接口,即使你不會 SQL 語句也可以使用數據庫。作者採用了鏈式編程的寫法,讓數據庫的管理變得優雅,可讀性也很強。

    SQLite.swift
    https://github.com/stephencelis/SQLite.swift
    https://www.itread01.com/p/386972.html


    Realm

    在各平臺封裝、優化的優勢,較受移動開發者青睞。對於iOS開發者,key-value 的實現直接易懂,可以像使用 NSDictionary 一樣使用 Realm。並且 ORM 徹底,省去了拼裝 Object 的過程。但其對代碼侵入性很強,Realm 要求類繼承 RLMObject 的基類。這對於單繼承的 Objective-C 意味着不能再繼承其他自定義的子類。同時,key-value 數據庫對較爲複雜的查詢場景也比較無力。


    FMDB

    眾多開發者長期的使用經驗後發現,有性能瓶頸,比如說某個用戶長期未登錄,在登錄時收到大量消息,由於 FMDB 不支持多線程的寫操作,會導致寫入很慢。

    基於 SQLite 封裝,對於有 SQLite 和 Objective-C 基礎的開發者來說,簡單易懂,可以直接上手;而缺點也正是在此,FMDB 只是將 SQLite 的 C 接口封裝成了 Objective-C 接口,沒有做更多優化,即所謂的膠水代碼 (Glue Code)。使用過程需要用大量的代碼拼接 SQL、拼裝 Object,既不方便也難以防止 SQL 注入。

    如何使用 FMDB: https://medium.com/@mikru168/c9a3dc148c3c


    WCDB

    貼一份評論


    WCDB.swift 使用官方文檔:
    https://github.com/Tencent/wcdb/wiki/Swift-%E5%A2%9E%E5%88%A0%E6%9F%A5%E6%94%B9

    https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/642941/
    https://www.zhihu.com/question/60914681

    https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/608382/

    https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/608379/

    https://www.twblogs.net/a/5c64f8f1bd9eee06ee22b624




    程式語言編年史

    程式語言編年史原文 下面這張圖片描繪了整個程式語言的歷史。包括各種程式語言的發明人、程式語言的特點和適用領域、被什麼網站或公司使用等 (檢視 完整高清圖 )。 之所以會有那麼多不同的程式語言是因為設計程式語言的初衷不同、對語言學習曲線的追求不同、不同程式之間的執行成本差異...