ios對象存儲
① iOS數據存儲(一)介紹
iOS本地化存儲的數據保存在沙盒中。
(1) Documents :iTunes會備份該目錄。一般用來存儲需要持久化的數據。
(2) Library/Caches :緩存,iTunes不會備份該目錄。內存不足時會被清除,應用沒有運行時,可能會被清除。一般存儲體積大、不需要備份的非重要數據。
(3) Library/Preference :iTunes同會備份該目錄,可以用來存儲一些偏好設置。
(4) tmp : iTunes不會備份這個目錄,用來保存臨時數據,應用退出時會清除該目錄下的數據。
獲取沙盒文件:
其中:
可以把字典或數組直接寫入到文件中。另外, NSString 、 NSData 、 NSNumber 等類型,也可以使用 writeToFile:atomically: 方法直接將對象寫入文件中,只是 Type 為空。
NSUserDefaults是輕量級存儲,一般使用它來進行一些設置的記錄,比如用戶ID,開關是否打開等設置,通過鍵值對的方式記錄設置,所以這個有時候也被稱為偏好設置。
NSUserDefaults可以存儲的數據類型包括: NSData 、 NSString 、 NSNumber 、 NSDate 、 NSArray 、 NSDictionary 。如果要存儲其他類型,則需要轉換為前面的類型,才能用NSUserDefaults存儲。
也可以寫成宏定義
② 第五篇:IOS類探究(成員變數值放在哪裡,成員變數信息放在哪裡)
我們簡單寫個demo,在我們定義的類HPWPerson里放了name,age屬性,還有_hobby成員變數
首先我們考慮兩個問題,類方法是放在哪裡?成員變數是放在哪裡?帶著這兩個問題我們進行深入的探究下。
我們通過上篇結尾的分析其實知道,實例方法,成員屬性,協議等都是存放在class_rw_t這個結構體里,如下面源碼所示,
我們繼續在class_rw_t結構體源碼里找下,發現有class_ro_t這個結構體,這個結構體是干什麼的呢?
我們通過列印得到如下:
@property (nonatomic ,) NSString *name;這個會生成下劃線的成員變數_name,
@property (nonatomic ,assign) int age;這個會生成下劃線的成員變數_age,
發現我們再列印class_ro_t里發現有上圖所示的成員變數,所以其中「_hobby」,「_age」,"_name"這些是存在class_ro_t這個結構里的。
通過上面我們發現,成員變數的值是放在對象里,成名變數名字以及一些大小信息放在類裡面,這個是為什麼呢?其實類裡面的結構體它就好比山坦一個模板,通過這個模板就可以生成各個成員變數信息,但是成員變數的值是不同的所以成員變數的值要存放在實例對象里,成員變數名及大小信息放在類裡面就可以。
接著我們再繼續探究下,在class_rw_t這個結構體里有class_ro_t這個結構體,那這兩個結構體有什麼關系呢?
1.class_ro_t是在編譯的時候生成的(只讀),是一個純凈的空間,不能被修改的
我們知道蘋果的runtime可以動態的修改屬性和方法,但是ro里又不支持修改的,那它是如何實現的呢?
我們先看下WWDC里的一個視頻講解:
WWDC講解ro,rw鏈接
通過上面的視頻我罩唯舉們知道,ro在編譯的時候生成,在內存不夠的時候就會進行移除,當要使用的時候就會重新從磁碟里去載入。在objc源碼里我們發現有個叫class_rw_ext_t的結構體,簡稱為rwe。class_rw_ext_t這個也不是每個類里都生成的,因為生成class_rw_ext_t是有條件的:或者有分類,或者runtime API修改的時候會生成這個rwe結構體。runtime是無法修改成員變數的,rwe在對ro里進行拷貝出的也是其中一部分,一般ro里也就10%的內容需要修改。接著我們看rwe源碼如下,也驗證了我們這點:如果有rwe就直接返回裡面的methods,沒有就返回ro里的baseMethods。
屬性存放在rw里源碼:如果有rwe就直接返回裡面的properties,沒有就返回ro里的baseProperties。
協議存放在rw里源碼:如果有rwe就直接返回裡面的protocols,沒有就返回ro里的baseProtocols。
設計元類只是單獨為了存放我們的類方法嗎?
其實其目的是為了復用消息機制。在OC中調⽤⽅法,其實是在給某個對象發送某條消息。
消息的發送在編譯的時候編譯器就會把⽅法轉換為objc_msgSend這個函數。
id objc_msgSend(id self, SEL op, ...) 這個函數有倆個隱式的參數:消息的接收者,消息的⽅法
名。通過這倆個參數就能去找到對應⽅法的實現。
objc_msgSend函數就會通過第⼀個參數消息的接收者的isa指針,找到對應的類,如果我們是通過
實例對象調⽤⽅法,那麼這個isa指針就會找到實例對象的類對象,如果是類對象,就會找到類對
象的元類對象,然後再通過SEL⽅法名找到對應的imp,然後就能找到⽅法對應的實現。
那如果沒有元類的話,那這個objc_msgSend⽅法還得多加倆個參數,⼀個參數⽤來判斷這個⽅法
到底是類⽅法還是實例⽅法。⼀個參數⽤來判斷消息的接受者到底是類對象還是實例對象。
消息的發送,越快越好。那如果沒物碧有元類,在objc_msgSend內部就會有有很多的判斷,就會影響
消息的發送效率。
所以元類的出現就解決了這個問題,讓各類各司其職,實例對象就⼲存儲屬性值的事,類對象存儲
實例⽅法列表,元類對象存儲類⽅法列表,符合設計原則中的單⼀職責,⽽且忽略了對對象類型的
判斷和⽅法類型的判斷可以⼤⼤的提升消息發送的效率,並且在不同種類的⽅法⾛的都是同⼀套流
程,在之後的維護上也⼤⼤節約了成本。
所以這個元類的出現,最⼤的好處就是能夠復⽤消息傳遞這套機制。不管你是什麼類型的⽅法,都
是同⼀套流程。
接著我們如何證明我們上面所說的呢?下面我們來看下在源碼里設置斷點調試:
首先我們打開objc的源碼,
我們一直按上面去列印,最後會列印一個classMethod這個類方法,在我們設置HPWPerson這個類里也有這個方法,如下,所以證明了類方法是存放在元類裡面的。
接著我們看些runtime的api方法的實現:
上面這些我們是用runtime的api把成員變數,實例方法,類方法等列印出來。
通過上面總結:
1)ro里存放成員變數,實例方法,屬性,協議,類對象
2)類方法存放在元類裡面
③ ios 中數組中存儲自定義的對象,怎麼將這個數組保存成本地文件
第一步:要將數組中的對象需要遵循 NSCoding 協議,實現協議中的兩個方法。
第二步:通過 NSKeyedArchive 進行快速歸檔,它會自動寫到文件中,讀取可以使用 NSKeyedUnarchiver 來解壓
代碼例子在網上都能找到。
④ ios開發中數據持久化有哪幾種,分別什麼時間使用
1、plist文件(屬性列表),通常用於儲存用戶設置,也可以用於存儲捆綁的信息;
2、preference(偏好設置),常用於保存少量數據;
3、NSKeyedArchiver(歸檔),將內存中的對象實例保存成binary到磁碟並且可以逆向這個過程用來保存用戶操作狀態等;
4、sqlite 3,使用資料庫進行存儲;
5、CoreData,它提供了對象-關系映射(ORM)的功能,即能夠將OC對象轉化成數據,保存在SQLite資料庫文件中,也能夠將保存在資料庫中的數據還原成OC對象。
⑤ iOS存儲技術-Keychain
鑰匙串這個技術大家每天都在用,它相當於一個容器,裡面有已加密的和未加密的用戶信息,它是怎麼實現安全儲存Mac、App、伺服器和網站的帳戶,開發過程中又該怎麼使用這個技術呢。通過一個例子來介紹一下:
用戶要登錄你的APP,這個時候用戶在文本框輸入了他的用戶信息和密碼,那麼你該如何存儲這個信息?自然我們會有一個類似用戶的結構來存儲用戶信息
這個結構里有一個String類型的用戶名稱和一個String類型的密碼變數, 張三輸入了它自己的用戶名「zhangsan」和密碼「******」來登陸,那麼我們就會有一個生成用戶的過程
那麼接下來你希望存儲到Keychain中,Keychain有哪些方法呢?第一步自然是添加
函數有三個參數,但是每個似乎都不認識,所以我們先簡單看一下這三個參數要做什麼
第一個參數是個字典,那自然是由許多key-value構成,首先它要包含一個這個數據的類型,數據類型使用kSecClass來做key,kSecClass的定義:
可以看到kSecClass是一個CFString類型的全局變數,它其中可用的值由Item Class Keys and Values列出。根據數據類型的不同有不同的值,例如密碼、認證,對於密碼它的值定義為:
也是一個CFString類型的變數, class對應的值會決定數據是否被加密,當選擇這個password的時候數據就會被加密。那麼我們字典中的第一個key-value對就有了:
那麼這個字典還需要包含什麼呢? 賬號:也就是這個數據是誰的數據,這個屬性由kSecAttrAccount這個Key來定義,同樣它也是一個CFString類型的Key,它的值是你自定義的一個CFString類型的值。當然這個屬性並不是必須的,於是字典中的第二個key-value對也有了
⚠️注意
字典中除了用戶名還需要用戶的數據,數據使用kSecValueData這個Key來定義,同樣是CFString類型的Key,但是用戶的數據可能多種多樣,所以它的值類型是CFData。那麼就需要把用戶的信息加工一下
這樣就得到了字典中第三個key-value對:
既然是鑰匙串,那就不能隨時隨地訪問,需要訪問控制許可權,所謂訪問控制就是你希望當iPhone解鎖的時候,或者是驗證了用戶的指紋之後才能繼續進行的過程。許可權由kSecAttrAccessControl這個Key來表示,它所對應的值是一個SecAccessControl的實例,而SecAccessControl又是什麼?
它就是一個包含Keychain對象怎麼被使用的信息的一個不透明類型,來看看它的實例化
它通過(CFAllocatorRef allocator, CFTypeRef protection, SecAccessControlCreateFlags flags, CFErrorRef _Nullable *error)函數來創建
函數有四個參數:
1.第一個參數是用來初始化SecAccessControlRef對象的. 我們可以傳 NULL 或者kCFAllocatorDefault
2.第二個參數是控制設備什麼情況下可以訪問這個Keychain信息, 它的值可以是添加Keychain函數的第一個參數字典中的一個其它key(kSecAttrAccessible)對應的值,例如可以控制當設備解鎖的時候使用的值:: CFString。其它可使用的還有(只有這台設備且設置了密碼)、(只有這個設備第一次解鎖後)。
3.第三個參數是一組額外的訪問控制:用來控制用戶級別的訪問許可權,如果設備沒有密碼總是處於unlocked的狀態,你可能希望進一步限制KeyChain訪問。例如在獲取銀行賬戶的認證時候,需要在獲取認證信息之前驗證是不是授權用戶在操作,這使得KeyChain可以根據用戶的輸入來管理對Keychain的訪問,可以選擇devicePasscode來限制需要用戶需要輸入密碼或者是選擇userPresence來讓系統根據當前狀態選擇一種驗證方式或者是多種方式的組合
第四個是失敗原因的一個指針,這里暫時傳一個nil值
所以我們可以通過來獲得一個訪問控制的參數
⚠️注意
現在我們可以回到之前創建函數的第一個參數字典的分析了,我們得到了
SecAccessControl的實例,所以字典的第四個key-value對也有了:
現在字典中有了數據的類型、哪個用戶的數據、用戶要存儲的數據、什麼條件可以訪問這個數據。看起來不缺少什麼了。我們的一個字典參數就處理好了:
函數會通過第二個參數來返回新添加的Keychain,具體的類型是根據第一個參數中指定的返回類型決定的(例如可以通過kSecReturnData這個可以指定返回類型為CFData) 當然,通常我們可以忽略這個返回的數據,所以可以傳一個nil值
函數還有一個返回值,從聲明上看是一個OSStatus類型的值,相應的定義在Security Framework Result Codes中,常見的值有:
我們通常需要將返回值和已知的返回值相比較來判斷是否操作成功了,也就是我們通常可以使用如下的語句來處理添加操作
至此,添加操作就完成了。
查詢主要使用SecItemCopyMatching(CFDictionaryRef query, CFTypeRef _Nullable *result)函數,函數會返回一個或者多個item,或者是指定的item屬性的,默認情況下只會返回匹配的第一個結果。
函數的第一個參數就是和添加Keychain函數的參數一樣的結構,通常有Keychain的class也就是由kSecClass為Key的一個key-value對。
屬性:屬性就是Keychain結果需要符合的條件,例如想查找哪個用戶的數據,查詢參數還可以帶控制返回的key,因為添加方法和查詢方法都會返回結果的數據和屬性到提供的參數指針里,所以可以指定返回的key來控制指針對應的返回數據的格式,也就是通常的密碼查詢應該包含kSecReturnData為Key的key-value對。
例如可以使用kSecReturnPersistentRef這個Key來獲得一個CFData的引用,然後可以把它存儲在磁碟或在進程間傳遞,可以在這之後調用另一個SecItemCopyMatching函數將持久化引用轉為常規引用,函數參數里需要將持久化的引用的數組作為kSecMatchItemList的值傳入。如果使用kSecReturnData來控制返回data本身,搜索會返回一個代表實際數據的CFData,這個就是典型的密碼Keychain的使用方式。同時,Keychain服務會在返回給你之前對數據進行解密
搜索參數:這個參數可以包含一些結果的數量條件,控制string屬性是否大小寫敏感等。
所以,希望查詢上面的用戶信息的時候查詢字典參數會如下所示
函數的第二個參數是一個CFTypeRef類型的接收函數返回的指針,我們需要先定義一個這樣的指針:
同樣我們需要判斷函數返回值是否成功:
因為查詢字典參數里攜帶了kSecReturnData,所以這個指針指向的數據類型是一個CFData類型的參數,我們需要獲取對應的值
這樣 str就是我們之前存儲在KeyChain中的用戶信息了
至此,Keychain的添加和刪除都已經具備了,基本的用戶需求就解決了。
除了基礎的使用之外,我們還可以
這些,下次再說吧
⑥ iOS開發怎麼獲取本地數據和把數據存儲到本地
一般獲取本地數據是從plist文件中讀取JSON數據。
讀取數據:
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"city" ofType:@"plist"];
NSArrary *cityArray = [[NSArray alloc]initWithContentsOfFile:plistPath];
這里的cityArray根據你存在plist中的數據類型來確定,如果plist中是字典類型,那麼你這里需要使用NSDictionary去存儲你從plist中獲取到的數據。
至於本地存儲數據的話根據你項目的具體功能來設計,一般的小型數據如用戶昵稱、手機號等使用NSUserDefault即可,但是如果是大量數據如賬單類app中的賬單數據那麼此時需要考慮使用sqlite3去存儲數據,至於密碼之類就需要使用NSKeydArchiver去存儲。
⑦ iOS開發之數據存儲以及刪除
iOS本地數據保存有多種方式,歸納如下:
本章不僅是學習多種數據存儲方式,也可學習到其他知識點,下面就讓我們詳細來看:
具體方培梁核法為:
第一步:獲得文件即將保存的路徑,並生成在該路徑下的文件:
第二步:往文件中寫入/讀取:
方法一:
方法配掘二:
方法三:
2.NSUserDefaults:是一個單例對象,在整個應用程序的生命周期中都只有一個實例。用渣旅來保存應用程序設置和屬性、用戶保存的數據。存儲在沙盒的Library/Preference中,NSUserDefaults可以存儲的數據類型包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。寫入和讀取都比較簡單,如下:
寫入:
NSString *str = [userDefault objectForKey:@"gang"];
@interface Person : NSObject <NSCoding>//遵守NSCoding協議
@property (nonatomic,strong) NSString *name;
@property (nonatomic,assign) NSInteger age;
@end
解檔操作:
同樣調用NSCoder子類NSKeyedArchiver的方法unarchiveRootObject:toFile: 即可
[NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
[archiver encodeObject:person forKey:@"person"];
[archiver encodeObject:bir forKey:@"bir"];
// 存檔完畢(一定要調用這個方法)
[archiver finishEncoding];
[data writeToFile:path atomically:YES];
NSData *undata = [NSData dataWithContentsOfFile:path];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data];
[unarchiver decodeObjectForKey:@"person"];
[unarchiver decodeObjectForKey:@"bir"];
// 恢復完畢
[unarchiver finishDecoding];