简体   繁体   English

如何获得NSCoder来编码/解码Swift结构数组?

[英]How can I get an NSCoder to encode/decode a Swift array of structs?

I have an object that must conform to NSCoding and that holds an array of UInt64 values. 我有一个必须符合NSCoding的对象,并且该NSCoding包含UInt64值的数组。 How can I encode/decode it with an NSCoder at all? 如何使用NSCoder对其进行编码/解码? Bonus question: how can I encode it most compactly? 额外的问题:如何最紧凑地编码? (It has to go into saved Game Center state data, whose size is limited.) (它必须进入已保存的Game Center状态数据,其大小是有限的。)

Ideally, I just want to write an Int which is the size n of the array, and then write n times the 64 bits of a UInt64 , and read it similarly. 理想情况下,我只想写的Int它的大小n阵列的,然后写n倍的64位UInt64 ,并且类似地读取它。 Can I do this? 我可以这样做吗?

coder.encodeObject(values, forKey: "v") doesn't work. coder.encodeObject(values, forKey: "v")不起作用。

class MyObject: NSCoding {

    private var values: [UInt64]

    // …

    // MARK: - NSCoding

    required init(coder decoder: NSCoder) {
        // ???
    }

    func encodeWithCoder(coder: NSCoder) {
        // ???
    }


}

Here is a possible solution that encodes the UInt64 array as an array of bytes. 这是将UInt64数组编码为字节数组的可能解决方案。 It is inspired by the answers to How to serialize C array with NSCoding? 它的灵感来自于如何使用NSCoding序列化C数组? .

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")
    }
}

Test: 测试:

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, 2, 3, 18446744073709551615]

Update for Swift 3 (Xcode 8): 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, 2, 3, UInt64.max])
let data = NSKeyedArchiver.archivedData(withRootObject: obj)

let dec = NSKeyedUnarchiver.unarchiveObject(with: data) as! MyObject
print(dec.values) // [1, 2, 3, 18446744073709551615]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM