我有一个必须符合NSCoding并且包含一组UInt64值的对象.如何使用NSCoder对其进行编码/解码?额外问题:如何最紧凑地编码? (它必须进入保存的Game Center状态数据,其大小有限.)
理想情况下,我只想写一个Int,它是数组的大小n,然后写入n次64位的UInt64,并以类似方式读取它.我可以这样做吗?
coder.encodeObject(values,forKey:“v”)不起作用.
- class MyObject: NSCoding {
- private var values: [UInt64]
- // …
- // MARK: - NSCoding
- required init(coder decoder: NSCoder) {
- // ???
- }
- func encodeWithCoder(coder: NSCoder) {
- // ???
- }
- }
这是一个将UInt64数组编码为的可能解决方案
一个字节数组.它的灵感来自 How to serialize C array with NSCoding?的答案.
一个字节数组.它的灵感来自 How to serialize C array with NSCoding?的答案.
- class MyObject: NSObject,NSCoding {
- var values: [UInt64] = []
- init(values : [UInt64]) {
- self.values = values
- }
- // MARK: - NSCoding
- required init(coder decoder: NSCoder) {
- super.init()
- var count = 0
- // decodeBytesForKey() returns an UnsafePointer<UInt8>,pointing to immutable data.
- let ptr = decoder.decodeBytesForKey("values",returnedLength: &count)
- // If we convert it to a buffer pointer of the appropriate type and count ...
- let buf = UnsafeBufferPointer<UInt64>(start: UnsafePointer(ptr),count: count/sizeof(UInt64))
- // ... then the Array creation becomes easy.
- values = Array(buf)
- }
- func encodeWithCoder(coder: NSCoder) {
- // This encodes both the number of bytes and the data itself.
- coder.encodeBytes(UnsafePointer(values),length: values.count * sizeof(UInt64),forKey: "values")
- }
- }
测试:
- let obj = MyObject(values: [1,2,3,UInt64.max])
- let data = NSKeyedArchiver.archivedDataWithRootObject(obj)
- let dec = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! MyObject
- print(dec.values) // [1,18446744073709551615]
更新Swift 3(Xcode 8):
- class MyObject: NSObject,NSCoding {
- var values: [UInt64] = []
- init(values : [UInt64]) {
- self.values = values
- }
- // MARK: - NSCoding
- required init(coder decoder: NSCoder) {
- super.init()
- var count = 0
- // decodeBytesForKey() returns an UnsafePointer<UInt8>?,pointing to immutable data.
- if let ptr = decoder.decodeBytes(forKey: "values",returnedLength: &count) {
- // If we convert it to a buffer pointer of the appropriate type and count ...
- let numValues = count / MemoryLayout<UInt64>.stride
- ptr.withMemoryRebound(to: UInt64.self,capacity: numValues) {
- let buf = UnsafeBufferPointer<UInt64>(start: UnsafePointer($0),count: numValues)
- // ... then the Array creation becomes easy.
- values = Array(buf)
- }
- }
- }
- public func encode(with coder: NSCoder) {
- // This encodes both the number of bytes and the data itself.
- let numBytes = values.count * MemoryLayout<UInt64>.stride
- values.withUnsafeBufferPointer {
- $0.baseAddress!.withMemoryRebound(to: UInt8.self,capacity: numBytes) {
- coder.encodeBytes($0,length: numBytes,forKey: "values")
- }
- }
- }
- }
- let obj = MyObject(values: [1,UInt64.max])
- let data = NSKeyedArchiver.archivedData(withRootObject: obj)
- let dec = NSKeyedUnarchiver.unarchiveObject(with: data) as! MyObject
- print(dec.values) // [1,18446744073709551615]