关于 NSCoding 和 NSKeyedArchiver | 咖啡时间

关于 NSCoding 和 NSKeyedArchiver | 咖啡时间_第1张图片

我们在开发应用的时候,经常会进行一些简单数据的存储,比如应用的一些配置信息。关于数据的存储就会用到 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 中。

这样,NSCodingNSKeyedArchiver 在一起使用,不但能够进行 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 协议后,就可以通过 NSKeyedArchiverNSKeyedUnarchiver 将他们自由的存取了:

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

关于 NSCoding 和 NSKeyedArchiver | 咖啡时间_第2张图片

你可能感兴趣的:(关于 NSCoding 和 NSKeyedArchiver | 咖啡时间)