李洪強iOS經典面試題144-數據存儲

李洪強iOS經典面試題144-數據存儲

 

數據存儲

sqlite中插入特殊字符的方法和接收處處理方法。

除’其餘的都是在特殊字符前面加「/」,而 ' -> '' 。方法:keyWord = keyWord.replace("/","//");css

什麼是NSManagedObject模型?

NSManagedObjcet是NSObject的子類,Core Date的重要組成部分。是一個通用類,實現了Core Date模型層所需的基本功能,用戶能夠經過NSManagedObjcet創建本身的數據模型。html

你實現過多線程的Core Data麼?NSPersistentStoreCoordinator,NSManagedObjectContext和NSManagedObject中的哪些須要在線程中建立或者傳遞?你是用什麼樣的策略來實現的?

1> CoreData是對SQLite數據庫的封裝 2> coreData中有三個對象是必須掌握的, NSManagedObject :只要定義一個類繼承於該類就會建立一張與之對應的表, 也就是一個繼承於該類的類就對應一張表. 每個經過繼承該類建立出來的對象,都是該類對應的表中的一條數據 NSManagedObjectContext: 用於操做數據庫, 只要有類它就能對數據庫的表進行增刪改查 NSPersistentStoreCoordinator: 決定數據存儲的位置 (SQLite/XML/其它文件中) 3> Core data自己並非一個併發安全的架構因此在多線程中實現Core data會有問題.問題在於 >2.1 CoreData中的NSManagedObjectContext在多線程中不安全 >2.2若是想要多線程訪問CoreData的話,最好的方法是一個線程一個NSManagedObjectContext >2.3每一個NSManagedObjectContext對象實例均可以使用同一個NSPersistentStoreCoordinator實例,這是由於NSManagedObjectContext會在便用NSPersistentStoreCoordinator前上鎖

簡單描述下客戶端的緩存機制?

  • 緩存能夠分爲:內存數據緩存、數據庫緩存、文件緩存
    • 每次想獲取數據的時候
    • 先檢測內存中有無緩存
    • 再檢測本地有無緩存(數據庫\文件)
    • 最終發送網絡請求
    • 將服務器返回的網絡數據進行緩存(內存、數據庫、文件), 以便下次讀取

      什麼是序列化和反序列化,用來作什麼

  • 序列化把對象轉化爲字節序列的過程
  • 反序列化把直接序列恢復成對象
  • 把對象寫到文件或者數據庫中,而且讀取出來

OC中實現複雜對象的存儲

  • 遵循NSCoding協議,實現複雜對象的存儲,實現該協議後能夠對其進行打包或者解包,轉化爲NSDate

iOS中經常使用的數據存儲方式有哪些?

  1. 數據存儲有四種方案,NSUserDefault,KeyChain,File,DB.
  2. 其中File有三種方式:plist,Archiver,Stream
  3. DB包括core Data和FMDB

說一說你對SQLite的認識

  • SQLite是目前主流的嵌入式關係型數據庫,其最主要的特色就是輕量級、跨平臺,當前不少嵌入式操做系統都將其做爲數據庫首選。git

  • 雖然SQLite是一款輕型數據庫,可是其功能也毫不亞於不少大型關係數據庫。github

  • 學習數據庫就要學習其相關的定義、操做、查詢語言,也就是你們平常說得SQL語句。和其餘數據庫相比,SQLite中的SQL語法並無太大的差異,所以這裏對於SQL語句的內容不會過多贅述,你們能夠參考SQLite中其餘SQL相關的內容,這裏仍是重點講解iOS中如何使用SQLite構建應用程序。先看一下SQLite數據庫的幾個特色:面試

    • 基於C語言開發的輕型數據庫
    • 在iOS中須要使用C語言語法進行數據庫操做、訪問(沒法使用ObjC直接訪問,由於libqlite3框架基於C語言編寫)
    • SQLite中採用的是動態數據類型,即便建立時定義了一種類型,在實際操做時也能夠存儲其餘類型,可是推薦建庫時使用合適的類型(特別是應用須要考慮跨平臺的狀況時)
    • 創建鏈接後一般不須要關閉鏈接(儘管能夠手動關閉)
  • 在iOS中操做SQLite數據庫能夠分爲如下幾步(注意先在項目中導入libsqlite3框架):
    • 打開數據庫,利用sqlite3_open()打開數據庫會指定一個數據庫文件保存路徑,若是文件存在則直接打開,不然建立並打開。打開數據庫會獲得一個sqlite3類型的對象,後面須要藉助這個對象進行其餘操做。
    • 執行SQL語句,執行SQL語句又包括有返回值的語句和無返回值語句。
    • 對於無返回值的語句(如增長、刪除、修改等)直接經過sqlite3_exec()函數執行;
    • 對於有返回值的語句則首先經過sqlite3_prepare_v2()進行sql語句評估(語法檢測),而後經過sqlite3_step()依次取出查詢結果的每一行數據,對於每行數據均可以經過對應的sqlite3_column_類型()方法得到對應列的數據,如此反覆循環直到遍歷完成。固然,最後須要釋放句柄。

說一說你對FMDB的認識

  • FMDB是一個處理數據存儲的第三方框架,框架是對sqlite的封裝,整個框架很是輕量級但又不失靈活性,並且更加面向對象。FMDB有以下幾個特性:
    • FMDB既然是對於libsqlite3框架的封裝,天然使用起來也是相似的,使用前也要打開一個數據庫,這個數據庫文件存在則直接打開不然會建立並打開。這裏FMDB引入了一個MFDatabase對象來表示數據庫,打開數據庫和後面的數據庫操做所有依賴此對象。
    • 對於數據庫的操做跟前面KCDbManager的封裝是相似的,在FMDB中FMDatabase類提供了兩個方法executeUpdate:和executeQuery:分別用於執行無返回結果的查詢和有返回結果的查詢。固然這兩個方法有不少的重載這裏就不詳細解釋了。惟一須要指出的是,若是調用有格式化參數的sql語句時,格式化符號使用「?」而不是「%@」、等。
    • 咱們知道直接使用libsqlite3進行數據庫操做實際上是線程不安全的,若是遇到多個線程同時操做一個表的時候可能會發生意想不到的結果。爲了解決這個問題建議在多線程中使用FMDatabaseQueue對象,相比FMDatabase而言,它是線程安全的。
    • 將事務放到FMDB中去說並非由於只有FMDB才支持事務,而是由於FMDB將其封裝成了幾個方法來調用,不用本身寫對應的sql而已。其實在在使用libsqlite3操做數據庫時也是原生支持事務的(由於這裏的事務是基於數據庫的,FMDB仍是使用的SQLite數據庫),只要在執行sql語句前加上「begin transaction;」執行完以後執行「commit transaction;」或者「rollback transaction;」進行提交或回滾便可。另外在Core Data中你們也能夠發現,全部的增、刪、改操做以後必須調用上下文的保存方法,其實自己就提供了事務的支持,只要不調用保存方法,以前全部的操做是不會提交的。在FMDB中FMDatabase有beginTransaction、commit、rollback三個方法進行開啓事務、提交事務和回滾事務。

說一說你對Core Data的認識

Core Data使用起來相對直接使用SQLite3的API而言更加的面向對象,操做過程一般分爲如下幾個步驟:算法

  • 建立管理上下文
    建立管理上下能夠細分爲:加載模型文件->指定數據存儲路徑->建立對應數據類型的存儲->建立管理對象上下方並指定存儲。
    通過這幾個步驟以後能夠獲得管理對象上下文NSManagedObjectContext,之後全部的數據操做都由此對象負責。同時若是是第一次建立上下文,Core Data會自動建立存儲文件(例如這裏使用SQLite3存儲),而且根據模型對象建立對應的表結構。
  • 查詢數據
    對於有條件的查詢,在Core Data中是經過謂詞來實現的。首先建立一個請求,而後設置請求條件,最後調用上下文執行請求的方法。
  • 插入數據
    插入數據須要調用實體描述對象NSEntityDescription返回一個實體對象,而後設置對象屬性,最後保存當前上下文便可。這裏須要注意,增、刪、改操做完最後必須調用管理對象上下文的保存方法,不然操做不會執行。
  • 刪除數據
    刪除數據能夠直接調用管理對象上下文的deleteObject方法,刪除完保存上下文便可。注意,刪除數據前必須先查詢到對應對象。
  • 修改數據
    修改數據首先也是取出對應的實體對象,而後經過修改對象的屬性,最後保存上下文。

OC中有哪些數據存儲方式,各有什麼區別?

  • OC中有四種數據存儲方式:
    • NSUserDefaults,用於存儲配置信息
    • SQLite,用於存儲查詢需求較多的數據
    • CoreData,用於規劃應用中的對象
  • 使用基本對象類型定製的個性化緩存方案.
    • NSUserDefaults:對象中儲存了系統中用戶的配置信息,開發者能夠經過這個實例對象對這些已有的信息進行修改,也 能夠按照本身的需求建立新的配置項。
    • SQLite擅長處理的數據類型其實與NSUserDefaults差很少,也是基礎類型的小數據,只是從組織形式上不一樣。開發者能夠以關係型數據庫的方式組織數據,使用SQL DML來管理數據。通常來講應用中的格式化的文本類數據能夠存放在數據庫 中,尤爲是相似聊天記錄、Timeline等這些具備條件查詢和排序需求的數據。
    • CoreData是一個管理方案,它的持久化能夠經過SQLite、XML或二進制文件儲存。它能夠把整個應用中的對象建模並進行自動化的管理。從歸檔文件還原模型時CoreData並非一次性把整個模型中的全部數據都載入內存,而是根據運行時狀態,把被調用到的對象實例載入內存。框架會自動控制這個過程,從而達到控制內存消耗,避免浪費。 不管從設計原理仍是使用方法上看,CoreData都比較複雜。所以,若是僅僅是考慮緩存數據這個需求,CoreData絕對不是一個優選方案。
    • CoreData的使用場景在於:整個應用使用CoreData規劃,把應用內的數據經過CoreData建模,徹底基於CoreData架構應用。
    • 使用基本對象類型定製的個性化緩存方案:從需求出發分析緩存數據有哪些要求:按Key查找,快速讀取,寫入不影響正常操做,不浪費內存,支持歸檔。這些都是基本需求,那麼再進一步或許還須要固定緩存項數量,支持隊列緩存,緩存過時等。
      數據存儲這一塊, 面試常問, 你經常使用哪種數據存儲? 什麼是序列化? sqlite是直接用它仍是用封裝了它的第三方庫? 尤爲是會問sqlite和core data的區別?

iOS平臺怎麼作數據的持久化?coredata和sqlite有無必然聯繫?coredata是一個關係型數據庫嗎?

  • iOS中能夠有四種持久化數據的方式: 屬性列表、對象歸檔、SQLite3和Core Datasql

  • coredata可使你以圖形界面的方式快速的定義app的數據模型,同時在你的代碼中容易獲取到它。數據庫

  • coredata提供了基礎結構去處理經常使用的功能,例如保存,恢復,撤銷和重作,容許你在app中繼續建立新的任務。編程

  • 在使用coredata的時候,你不用安裝額外的數據庫系統,由於coredata使用內置的sqlite數據庫。數組

  • coredata將你app的模型層放入到一組定義在內存中的數據對象。

  • coredata會 追蹤這些對象的改變,同時能夠根據須要作相應的改變,例如用戶執行撤銷命令。

  • 當coredata在對你app數據的改變進行保存的時 候,core data會把這些數據歸檔,並永久性保存。

  • mac os x中sqlite庫,它是一個輕量級功能強大的關係數據引擎,也很容易嵌入到應用程序。能夠在多個平臺使用,sqlite是一個輕 量級的嵌入式sql數據庫編程。

  • 與coredata框架不一樣的是,sqlite是使用程序式的,sql的主要的API來直接操做數據表。

  • Core Data不是一個關係型數據庫,也不是關係型數據庫管理系統(RDBMS)。

  • 雖然Core Dta支持SQLite做爲一種存儲類型, 但它不能使用任意的SQLite數據庫。

  • Core Data在使用的過程種本身建立這個數據庫。Core Data支持對1、對多的關係。

若是後期須要增長數據庫中的字段怎麼實現,若是不使用CoreData呢?

  • 編寫SQL語句來操做原來表中的字段
  • 增長表字段:ALTER TABLE 表名 ADD COLUMN 字段名 字段類型;
  • 刪除表字段:ALTER TABLE 表名 DROP COLUMN 字段名;
  • 修改表字段:ALTER TABLE 表名 RENAME COLUMN 舊字段名 TO 新字段名;

SQLite數據存儲是怎麼用?

  • 添加SQLite動態庫:導入主頭文件:#import <sqlite3.h>
  • 利用C語言函數建立\打開數據庫,編寫SQL語句

簡單描述下客戶端的緩存機制?

  • 緩存能夠分爲:內存數據緩存、數據庫緩存、文件緩存
  • 每次想獲取數據的時候
  • 先檢測內存中有無緩存
  • 再檢測本地有無緩存(數據庫\文件)
  • 最終發送網絡請求
  • 將服務器返回的網絡數據進行緩存(內存、數據庫、文件)以便下次讀取

你實現過多線程的Core Data麼?NSPersistentStoreCoordinator,NSManagedObjectContext和NSManagedObject中的哪些須要在線程中建立或者傳遞?你是用什麼樣的策略來實現的?

  • CoreData是對SQLite數據庫的封裝
  • CoreData中的NSManagedObjectContext在多線程中不安全
  • 若是想要多線程訪問CoreData的話,最好的方法是一個線程一個NSManagedObjectContext
  • 每一個NSManagedObjectContext對象實例均可以使用同一個NSPersistentStoreCoordinator實例,這是由於NSManagedObjectContext會在便用NSPersistentStoreCoordinator前上鎖

Core Data數據遷移

博客地址: http://blog.csdn.net/jasonblog/article/details/17842535

FMDB的使用和對多張表的處理

博客地址: http://blog.csdn.net/wscqqlucy/article/details/8464398

說說數據庫的左鏈接和右鏈接的區別

  • 數據庫左鏈接和右鏈接的區別:主表不同經過左鏈接和右鏈接,最小條數爲3(記錄條數較小的記錄數),最大條數爲12(3×4)

  • 技術博客的地址 : http://www.2cto.com/database/201407/317367.html

iOS 的沙盒目錄結構是怎樣的? App Bundle 裏面都有什麼?

  1. 沙盒結構

    • Application:存放程序源文件,上架前通過數字簽名,上架後不可修改
    • Documents:經常使用目錄,iCloud備份目錄,存放數據,這裏不能存緩存文件,不然上架不被經過
    • Library
      • Caches:存放體積大又不須要備份的數據,SDWebImage緩存路徑就是這個
      • Preference:設置目錄,iCloud會備份設置信息
    • tmp:存放臨時文件,不會被備份,並且這個文件下的數據有可能隨時被清除的可能
  2. App Bundle 裏面有什麼

    • Info.plist:此文件包含了應用程序的配置信息.系統依賴此文件以獲取應用程序的相關信息
    • 可執行文件:此文件包含應用程序的入口和經過靜態鏈接到應用程序target的代碼
    • 資源文件:圖片,聲音文件一類的
    • 其餘:能夠嵌入定製的數據資源

你會如何存儲用戶的一些敏感信息,如登陸的 token

使用keychain來存儲,也就是鑰匙串,使用keychain須要導入Security框架

自定義一個keychain的類
#import <Security/Security.h> @implementation YCKKeyChain +(NSMutableDictionary *)getKeychainQuery:(NSString *)service { return [NSMutableDictionary dictionaryWithObjectsAndKeys: (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass, service, (__bridge_transfer id)kSecAttrService, service, (__bridge_transfer id)kSecAttrAccount, (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock, (__bridge_transfer id)kSecAttrAccessible, nil]; } +(void)save:(NSString *)service data:(id)data { // 得到搜索字典 NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; // 添加新的刪除舊的 SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery); // 添加新的對象到字符串 [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData]; // 查詢鑰匙串 SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL); } +(id)load:(NSString *)service { id ret = nil; NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; // 配置搜索設置 [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData]; [keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey: (__bridge_transfer id)kSecMatchLimit]; CFDataRef keyData = NULL; if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) { @try { ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData]; } @catch (NSException *e) { NSLog(@"Unarchive of %@ failed: %@", service, e); } @finally { } } return ret; } +(void)delete:(NSString *)service { NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery); }

在別的類實現存儲,加載,刪除敏感信息方法
// 用來標識這個鑰匙串
static NSString const KEY_IN_KEYCHAIN = @"com.yck.app.allinfo";
// 用來標識密碼
static NSString 
const KEY_PASSWORD = @"com.yck.app.password";

+(void)savePassWord:(NSString *)password { NSMutableDictionary *passwordDict = [NSMutableDictionary dictionary]; [passwordDict setObject:password forKey:KEY_PASSWORD]; [YCKKeyChain save:KEY_IN_KEYCHAIN data:passwordDict]; } +(id)readPassWord { NSMutableDictionary *passwordDict = (NSMutableDictionary *)[YCKKeyChain load:KEY_IN_KEYCHAIN]; return [passwordDict objectForKey:KEY_PASSWORD]; } +(void)deletePassWord { [YCKKeyChain delete:KEY_IN_KEYCHAIN]; }

使用 NSUserDefaults 時,如何處理布爾的默認值?(好比返回 NO,不知道是真的 NO 仍是沒有設置過)

if([[NSUserDefaults standardUserDefaults] objectForKey:ID] == nil){ NSLog(@"沒有設置"); }

MD5和Base64的區別是什麼,各自使用場景是什麼?

作過加密相關的功能的,幾乎都會使用到MD5和Base64,它們二者在實際開發中是最經常使用的。
•    MD5:是一種不可逆的摘要算法,用於生成摘要,沒法逆着破解獲得原文。經常使用的是生成32位摘要,用於驗證數據的有效性。好比,在網絡請求接口中,經過將全部的參數生成摘要,客戶端和服務端採用一樣的規則生成摘要,這樣能夠防篡改。又如,下載文件時,經過生成文件的摘要,用於驗證文件是否損壞。 • Base64:屬於加密算法,是可逆的,通過encode後,能夠decode獲得原文。在開發中,有的公司上傳圖片採用的是將圖片轉換成base64字符串,再上傳。在作加密相關的功能時,一般會將數據進行base64加密/解密。

plist文件是用來作什麼的。通常用它來處理一些什麼方面的問題。

  • plist是iOS系統中特有的文件格式。咱們經常使用的NSUserDefaults偏好設置實質上就是plist文件操做。plist文件是用來持久化存儲數據的。
  • 咱們一般使用它來存儲偏好設置,以及那些少許的、數組結構比較複雜的不適合存儲數據庫的數據。好比,咱們要存儲全國城市名稱和id,那麼咱們要優先選擇plist直接持久化存儲,由於更簡單。

當存儲大塊數據是怎麼作?

  • 你有不少選擇,好比:
  • 使用NSUerDefaults
  • 使用XML, JSON, 或者 plist
  • 使用NSCoding存檔
  • 使用相似SQLite的本地SQL數據庫
  • 使用 Core Data
  • NSUserDefaults的問題是什麼?雖然它很nice也很便捷,可是它只適用於小數據,好比一些簡單的布爾型的設置選項,再大點你就要考慮其它方式了
  • XML這種結構化檔案呢?整體來講,你須要讀取整個文件到內存裏去解析,這樣是很不經濟的。使用SAX又是一個很麻煩的事情。
  • NSCoding?不幸的是,它也須要讀寫文件,因此也有以上問題。
  • 在這種應用場景下,使用SQLite 或者 Core Data比較好。使用這些技術你用特定的查詢語句就能只加載你須要的對象。在性能層面來說,SQLite和Core Data是很類似的。他們的不一樣在於具體使用方法。Core Data表明一個對象的graph model,但SQLite就是一個DBMS。Apple在通常狀況下建議使用Core Data,可是若是你有理由不使用它,那麼就去使用更加底層的SQLite吧。若是你使用SQLite,你能夠用FMDB(https://GitHub.com/ccgus/fmdb)這個庫來簡化SQLite的操做,這樣你就不用花不少經歷瞭解SQLite的C API了

怎麼解決sqlite鎖定的問題

1> 設置數據庫鎖定的處理函數 int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); 函數能夠定義一個回調函數,當出現數據庫忙時,sqlite會調用該函數 當回調函數爲NULL時,清除busy handle,申請不到鎖直接返回 回調函數的第二個函數會被傳遞爲該由這次忙事件調用該函數的次數 回調函數返回非0,數據庫會重試當前操做,返回0則當前操做返回SQLITE_BUSY 2> 設定鎖定時的等待時間 int sqlite3_busy_timeout(sqlite3*, 60); 定義一個毫秒數,當未到達該毫秒數時,sqlite會sleep並重試當前操做 若是超過ms毫秒,仍然申請不到須要的鎖,當前操做返回sqlite_BUSY 當ms<=0時,清除busy handle,申請不到鎖直接返回

文章若有問題,請留言,我將及時更正。

相關文章
相關標籤/搜索