最近公司項目中使用了本地存儲蕉鸳,所以趁著周六日來整理一下在Swift中的幾種數(shù)據(jù)存儲方式辕近。
一抬虽、plist文件存儲
存儲目錄:Documents
每次在Xcode中新建一個iOS項目后脑题,都會自己產(chǎn)生一個.plist文件许师,里面記錄項目的一些配置信息肉渴。我們也可以自己創(chuàng)建.plist文件來進行數(shù)據(jù)的存儲和讀取公荧。
.plist文件其實就是一個XML格式的文件,支持的數(shù)據(jù)類型有NSDictionary同规、NSArray循狰、Boolean、NSData券勺、NSDate绪钥、NSNumber、NSString這些類型关炼。
在這里簡單說一下關(guān)于應用程序各個文檔所在的目錄:
-
Home目錄 ./
獲取方式:
let homePath = NSHomeDirectory()
打印出來以后程腹,可以復制到Finder->前往 -> 前往文件夾中,查看文檔儒拂。
正如我們看到的寸潦,在home下有三個文件夾,下面我們分別來看一下這三個目錄社痛。
-
1.Documents目錄 ./Documents
用戶文檔目錄见转,蘋果建議將程序中建立的或者在程序中瀏覽到的文件數(shù)據(jù)保存到該目錄下,iTunes備份和恢復的時候會包括此目錄
獲取方式:
//方法1
//swift 2
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0].stringByAppendingString("user")
//swift 3
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0].appending("user")
//方法2
let ducumentPath2 = NSHomeDirectory() + "/Documents"
-
2.Library目錄 ./Library
這個目錄下有兩個子目錄:Caches 和 Preferences
Library/Preferences目錄蒜哀,包含應用程序的偏好設(shè)置文件斩箫。iOS的Settings(設(shè)置)應用會在該目錄中查找應用的設(shè)置信息。不應該直接創(chuàng)建偏好設(shè)置文件撵儿,而是應該使用NSUserDefaults類來取得和設(shè)置應用程序的偏好乘客。
Library/Caches目錄,主要存放緩存文件淀歇,iTunes不會備份此目錄寨典,此目錄下文件不會再應用退出時刪除。一般存儲體積大房匆、不需要備份的非重要數(shù)據(jù)耸成。
//Library目錄-方法1
let libraryPaths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.LibraryDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let libraryPath = libraryPaths[0] as! String
//Library目錄-方法2
let libraryPath2 = NSHomeDirectory() + "/Library"
//Cache目錄-方法1
let cachePaths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let cachePath = cachePaths[0] as! String
//Cache目錄-方法2
let cachePath2 = NSHomeDirectory() + "/Library/Caches"
-
3.tmp目錄 ./tmp
保存應用運行時所需的臨時數(shù)據(jù),使用完畢后再將相應的文件從該目錄刪除浴鸿。重啟后清空井氢。應用沒有運行時,系統(tǒng)也可能會清除該目錄下的文件岳链。iTunes同步設(shè)備時不會備份該目錄花竞。
//方法1
let tmpDir = NSTemporaryDirectory()
//方法2
let tmpDir2 = NSHomeDirectory() + "/tmp"
說了半天還沒有給大家介紹怎么把數(shù)據(jù)寫入.plist文件中,我們下面以數(shù)組為例,來看一下:
let array = NSArray(objects: "apple","orange","pear","banana","watermelon")
let filePath:String = NSHomeDirectory() + "/Documents/fruit.plist"
array.writeToFile(filePath, atomically: true)
這個時候我們會看到在Documents文件夾下面產(chǎn)生了一個.plist文件约急,打開后會發(fā)現(xiàn)是我們剛剛存入的水果名稱零远。
存入plist后我們來讀取一下fruit.plist中的數(shù)據(jù):
let fruitArr = NSArray(contentsOfFile: NSHomeDirectory() + "/Documents/fruit.plist")
同理,我們還可以存入.plist文件支持的其他類型的數(shù)據(jù)厌蔽。
缺點:用.plist文件只能存儲含有writeToFile:方法的對象牵辣,局限性。
二奴饮、NSUserDefaults
存儲目錄:Library/Preference
用來保存應用程序設(shè)置和屬性纬向、用戶保存的數(shù)據(jù),用戶再次打開程序或開機后這些數(shù)據(jù)仍然存在戴卜。NSUserDefaults可以存儲的數(shù)據(jù)類型包括:NSData逾条、NSString、NSNumber投剥、NSDate师脂、NSArray、 NSDictionary江锨。如果要存儲其他類型,則需要轉(zhuǎn)換為前面的類型,才能用NSUserDefaults存儲危彩。很多iOS應用都支持偏好設(shè)置,比如保存用戶名泳桦、密碼汤徽、字體大小等設(shè)置,iOS提供了一套標準的解決方案來為應用加入偏好設(shè)置功能灸撰,每個應用都有個NSUserDefaults實例谒府,通過它來存取偏好設(shè)置,比如浮毯,保存用戶名完疫、字體大小、是否自動登錄等债蓝。
示例:
-
1.對原生數(shù)據(jù)類型的存儲和讀取
var userDefault = NSUserDefaults.standardUserDefaults()//AnyObject userDefault.setObject("apple", forKey: "Object") var objectValue:AnyObject? = userDefault.objectForKey("Object") //Int類型 userDefault.setInteger(12345, forKey: "Int") var intValue = userDefault.integerForKey("Int") //Float類型 userDefault.setFloat(3.2, forKey: "Float") var floatValue = userDefault.floatForKey("Float") //Double類型 userDefault.setDouble(5.2240, forKey: "Double") var doubleValue = userDefault.doubleForKey("Double") //Bool類型 userDefault.setBool(true, forKey: "Bool") var boolValue = userDefault.boolForKey("Bool") //NSURL類型 userDefault.setURL(NSURL(string:"http://baidu.com")!, forKey: "NSURL") var urlValue = userDefault.URLForKey("NSURL") //NSString類型 userDefault.setObject("apple", forKey: "NSString") var nsStringValue = userDefault.objectForKey("NSString") as! NSString //NSNumber類型 var number:NSNumber = NSNumber(int:22) userDefault.setObject(number, forKey: "NSNumber") number = userDefault.objectForKey("NSNumber") as! NSNumber //NSArray類型 var array:NSArray = NSArray(array: ["123","456"]) userDefault.setObject(array, forKey: "NSArray") //NSDictionaryy類型 var dictionary:NSDictionary = NSDictionary(dictionary: ["1":"apple"]) userDefault.setObject(dictionary, forKey: "NSDictionary") dictionary = userDefault.objectForKey("NSDictionary") as! NSDictionary
-
2.系統(tǒng)對象的存儲與讀取
系統(tǒng)對象實現(xiàn)存儲壳鹤,需要通過 archivedDataWithRootObject 方法轉(zhuǎn)換成 NSData 為載體,才可以存儲饰迹。下面以 UIImage 對象為例:
let userDefault = NSUserDefaults.standardUserDefaults()
//UIImage對象存儲
//將對象轉(zhuǎn)換成NSData流
let image = UIImage(named: "apple.png")
let imageData:NSData = NSKeyedArchiver.archivedDataWithRootObject(image!)
//存儲NSData對象
userDefault.setObject(imageData, forKey: "imageData")
//設(shè)置同步
userDefault.synchronize()//UIImage對象讀取 //獲取NSData let objData:NSData = userDefault.objectForKey("imageData") as! NSData //還原對象 let myImage = NSKeyedUnarchiver.unarchiveObjectWithData(objData) as! UIImage print(myImage)
-
3.自定義對象的存儲和讀取
如果想要存儲自己定義的類芳誓,首先需要對該類實現(xiàn) NSCoding 協(xié)議來進行歸檔和反歸檔(序列化和反序列化)。即該類內(nèi)添加 func encodeWithCoder(_encoder:NSCoder) 方法和 init(coder decoder:NSCoder) 方法啊鸭,將屬性進行轉(zhuǎn)換锹淌。
首先,我們定義一個model來存儲用戶的信息:
//----- 自定義對象類 -----
class UserInfo: NSObject {
var name:String
var phone:String//構(gòu)造方法 init(name:String="",phone:String=""){ self.name = name self.phone = phone super.init() } //從nsobject解析回來 init(coder aDecoder:NSCoder!){ self.name=aDecoder.decodeObjectForKey("Name") as! String self.phone=aDecoder.decodeObjectForKey("Phone") as! String } //編碼成object func encodeWithCoder(aCoder:NSCoder!){ aCoder.encodeObject(name,forKey:"Name") aCoder.encodeObject(phone,forKey:"Phone") } }
下面我們來存儲自定義對象
let userDefault = NSUserDefaults.standardUserDefaults()
//自定義對象存儲
let model = UserInfo(name: "貓咪", phone: "18800000000")
//實例對象轉(zhuǎn)換成NSData
let modelData:NSData = NSKeyedArchiver.archivedDataWithRootObject(model)
//存儲NSData對象
userDefault.setObject(modelData, forKey: "myModel")
//設(shè)置同步
userDefault.synchronize()
//自定義對象讀取
let myModelData = userDefault.objectForKey("myModel") as! NSData
_ = NSKeyedUnarchiver.unarchiveObjectWithData(myModelData) as! UserInfo
當我們退出登錄的時候赠制,我們可能會想清除本地的數(shù)據(jù)赂摆,我們可以通過removeObjectForKey() 方法可以刪除已保存的數(shù)據(jù)。當然如果這個存儲對象不存在也不會報錯。
NSUserDefaults.standardUserDefaults().removeObjectForKey("myModel")
注意:UserDefaults設(shè)置數(shù)據(jù)時烟号,不是立即寫入绊谭,而是根據(jù)時間戳定時地把緩存中的數(shù)據(jù)寫入本地磁盤。所以調(diào)用了set方法之后數(shù)據(jù)有可能還沒有寫入磁盤應用程序就終止了汪拥。出現(xiàn)以上問題达传,可以通過調(diào)用synchornize方法強制寫入userDefault.synchronize()
缺點: 本質(zhì)還是plist文件存儲,相對于plist文件存儲來講存儲數(shù)據(jù)更快捷.
三、NSKeyedArchiver(NSCoding)
如果對象是NSString喷楣、NSDictionary趟大、NSArray鹤树、NSData铣焊、NSNumber等類型,可以直接用NSKeyedArchiver進行歸檔和恢復罕伯,不是所有的對象都可以直接用這種方法進行歸檔曲伊,只有遵守了NSCoding協(xié)議的對象才可以。
NSCoding協(xié)議有2個方法:
encodeWithCoder:每次歸檔對象時追他,都會調(diào)用這個方法坟募。一般在這個方法里面指定如何歸檔對象中的每個實例變量,可以使用encodeObject:forKey:方法歸檔實例變量邑狸;
initWithCoder:每次從文件中恢復(解碼)對象時懈糯,都會調(diào)用這個方法。一般在這個方法里面指定如何解碼文件中的數(shù)據(jù)為對象的實例變量单雾,可以使用decodeObject:forKey方法解碼實例變量赚哗。
示例:
// 解檔 歸檔
required init?(coder aDecoder: NSCoder) {
access_token = aDecoder.decodeObjectForKey("access_token") as! String
expires_in = aDecoder.decodeDoubleForKey("expires_in")
expiresDate = aDecoder.decodeObjectForKey("expiresDate") as! NSDate
uid = aDecoder.decodeObjectForKey("uid") as! String
name = aDecoder.decodeObjectForKey("name") as? String
avatar_large = aDecoder.decodeObjectForKey("avatar_large") as? String
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(access_token, forKey: "access_token")
aCoder.encodeDouble(expires_in, forKey: "expires_in")
aCoder.encodeObject(expiresDate, forKey: "expires_in")
aCoder.encodeObject(uid, forKey: "uid")
aCoder.encodeObject(name, forKey: "name")
aCoder.encodeObject(avatar_large, forKey: "avatar_large")
}
歸檔路徑,swift中的類常量都是使用 static 來定義的
static let accountPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).last!.stringByAppendingPathComponent("account.plist")
在OC中硅堆,要注意:
如果父類也遵守了NSCoding協(xié)議屿储,請注意:
應該在encodeWithCoder:方法中加上一句[super encodeWithCode:encode];確保繼承的實例變量也能被編碼,也能被歸檔渐逃;
應該在initWithCoder:方法中加上一句self = [super initWithCoder:decoder];確保繼承的實例變量也能被解碼够掠,即也能被恢復;
但有時候可能想將多個對象寫入到同一個文件中茄菊,那么就要使用NSData來進行歸檔對象疯潭,NSData可以為一些數(shù)據(jù)提供臨時存儲空間,以便隨后寫入文件面殖,或者存放從磁盤讀取的文件內(nèi)容袁勺。
缺點: 歸檔的形式來保存數(shù)據(jù),只能一次性歸檔保存以及一次性解壓。所以只能針對小量數(shù)據(jù),而且對數(shù)據(jù)操作比較笨拙,即如果想改動數(shù)據(jù)的某一小部分,還是需要解壓整個數(shù)據(jù)或者歸檔整個數(shù)據(jù)畜普。
這一部分先整理到這里期丰,歡迎大家來指出不足~~~~~( _ )/~~拜拜