我们在开发应用的时候,经常会进行一些简单数据的存储,比如应用的一些配置信息。关于数据的存储就会用到 NSCoding 的概念,那么我们就来了解一下吧。
我们存储简单信息,最常用的就是 NSUserDefaults
类,它可以让我们用很方便的形式以键 - 值 的形式存储信息。比如我们可以这样:
NSUserDefaults.standardUserDefaults().setObject("Swift", forKey: "Book")
使用起来非常简单,当我们需要使用这个存储的值的时候,我们可以这样获取:
NSUserDefaults.standardUserDefaults().objectForKey("Book")
也非常的简单。NSUserDefaults
还提供了一些其他的便捷方法,让我们存储和读取各种类型的值:
public func setInteger(value: Int, forKey defaultName: String)
public func setFloat(value: Float, forKey defaultName: String)
public func setDouble(value: Double, forKey defaultName: String)
public func setBool(value: Bool, forKey defaultName: String)
public func setURL(url: NSURL?, forKey defaultName: String)
读取方法:
public func stringForKey(defaultName: String) -> String?
public func arrayForKey(defaultName: String) -> [AnyObject]?
public func dictionaryForKey(defaultName: String) -> [String : AnyObject]?
public func dataForKey(defaultName: String) -> NSData?
public func stringArrayForKey(defaultName: String) -> [String]?
public func integerForKey(defaultName: String) -> Int
public func floatForKey(defaultName: String) -> Float
public func doubleForKey(defaultName: String) -> Double
public func boolForKey(defaultName: String) -> Bool
public func URLForKey(defaultName: String) -> NSURL?
提供的接口非常丰富,那么,还有另外一种情况:
class Book {
var name:String?
var image:UIImage?
}
let book = Book()
NSUserDefaults.standardUserDefaults().setObject(book, forKey: "book")
我们如果编译,运行这段代码会有什么结果呢?存储成功? 还是:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object Samples.Book for key book'
恩,出现了运行时错误,这时因为我们的 Book 类是不能直接存入 NSUserDefaults
的,它需要实现 NSCoding
协议才可以进行这样的操作。
那么我们来对 Book
类进行一些修改:
class Book: NSObject, NSCoding {
var name:String?
var image:UIImage?
func encodeWithCoder(aCoder: NSCoder) {
}
override init() {
}
required init?(coder aDecoder: NSCoder) {
}
}
现在, Book 类实现了 NSCoding
协议,我们还没有对它进行具体的实现,只是定义了 NSCoding
的两个协议方法 encodeWithCoder(aCoder: NSCoder)
和 init?(coder aDecoder: NSCoder)
这两个方法用作将这个类进行编码和解码。我们稍后在做说明,接下来,我们就可以将他存储到 NSUserDefaults
中了:
let book = Book()
let data = NSKeyedArchiver.archivedDataWithRootObject(book)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "book")
我们这里用到了一个中间类 NSKeyedArchiver
,先是将 Book
通过 NSKeyedArchiver
编码成了 NSData
。 然后再将这个 NSData
存入到 NSUserDefaults
中。
NSKeyedArchiver
只能对实现了 NSCoding
协议的类进行编码,将它们转换成二进制数据,然后再存入 NSUserDefaults
中。
这样,NSCoding
和 NSKeyedArchiver
在一起使用,不但能够进行 NSUserDefaults
的存储,还能够进行对象的一些实体化和数据传输操作。
我们再来看一下实现 NSCoding
的具体方法, encodeWithCoder
为编码方法,用于将对象中的值转换成数据:
func encodeWithCoder(aCoder: NSCoder) {
if let name = self.name {
aCoder.encodeObject(name, forKey: "name")
}
if let image = self.image {
if let imageData = UIImagePNGRepresentation(image) {
aCoder.encodeObject(imageData, forKey: "image")
}
}
}
相应的,init?(coder aDecoder: NSCoder)
作为解码方法,用于将编码后的数据还原成对象:
required init?(coder aDecoder: NSCoder) {
self.name = aDecoder.decodeObjectForKey("name") as? String
if let imageData = aDecoder.decodeObjectForKey("image") as? NSData {
image = UIImage(data: imageData)
}
}
我们注意到,无论是编码和解码方法中,都将 self.image 属性先转换成 NSData 然后再进行编码解码操作。
我们完整的实现了 NSCoding
协议后,就可以通过 NSKeyedArchiver
和 NSKeyedUnarchiver
将他们自由的存取了:
let book = Book()
book.name = "Swift"
book.image = UIImage(named: "cover")
let data = NSKeyedArchiver.archivedDataWithRootObject(book)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "book")
读取:
if let bookData = NSUserDefaults.standardUserDefaults().objectForKey("book") as? NSData {
if let book = NSKeyedUnarchiver.unarchiveObjectWithData(bookData) as? Book {
print(book.name!)
}
}
更多精彩内容可关注微信公众号:
swift-cafe