iOS提供了幾種數據持久化保存的方法,有NSKeyedArchiver,Property List,NSUserDefaults和CoreData。我學習下來,覺得保存應用內的諸如列表,記錄這些東西,用NSKeyedArchiver是比較合適的。
它有些類似於操作系統中將文件壓縮存放,而它是將對象壓縮成一個文件存放在iOS設備的硬盤中。這樣的話即使將應用關閉,下次開啟時也能使用方法從硬盤將數據解壓縮出來,供用戶繼續操作這些數據。
讓對象可被NSKeyedArchiver存儲
如果想要使用NSKeyedArchiver保存系統預設類型的方法,那不用做什么額外的工作,直接調用方法保存即可。而如果要保存自己建立的類,則需要讓類繼承NSObject和協議NSCoding,並補上func encodeWithCoder(aCoder: NSCoder)
與required init?(coder aDecoder: NSCoder)
兩個對象。
例如,我們建立了一個對象Person,有String類型的name和Int類型的overall兩個屬性,那我們可以這么寫上述兩個方法來讓它變得可以用NSKeyedArchiver保存:
func encodeWithCoder(aCoder: NSCoder){
aCoder.encodeObject(name, forKey: "name")
aCoder.encodeObject(overall, forKey: "overall")
}
required init?(coder aDecoder: NSCoder) {
name = aDecoder.decodeObjectForKey("name") as! String
overall = aDecoder.decodeObjectForKey("overall") as! Int
}
保存
保存時需要輸入路徑和壓縮文件名。但是實際上路徑基本是固定的,因為其他位置幾乎都是不可寫的。文件名包括后綴都可以隨意定義。
let filePath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] + "/person.dat"
NSKeyedArchiver.archiveRootObject(person, toFile: filePath)
讀取
讀取時需要注意的是,讀取出來的對象是作為NSObject類存在的,用戶需要自行轉為正確的類。
let filePath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] + "/person.dat"
if let person : Person = NSKeyedUnarchiver.unarchiveObjectWithFile(filePath) as? Person{
//處理
}
我遇到的問題
其實抱怨這個問題就是這篇文章我主要目的。我之前做的demo在模擬器上運行毫無問題,但是插上手機在實機上測試,就保存失敗了!搜索了半天資料,發現stackoverflow上有個人與我遇到了同樣的問題。后來經過調試,原來是我路徑中沒有加"/"。如果不加“/”,就變成了在應用主目錄下生成一個Documentsperson.dat的文件,而不是在Documents文件夾下生成person.dat。在模擬器上,你是可以在任何文件夾下生成文件的,而實機上的權限控制就比較嚴格,Documentsperson.dat就會生成失敗。
也是因為我選擇的參考書並不靠譜(日本人藤田泰介所著的《プロの力が身につく iPhone/iPadアプリケーション開発の教科書》),因為它里面的路徑就沒有加“/”。作者估計模擬器跑通了就這樣寫上去了吧。