How can I get an NSCoder to encode/decode a Swift array of structs? -
i have object must conform nscoding
, holds array of uint64
values. how can encode/decode nscoder
@ all? bonus question: how can encode compactly? (it has go saved game center state data, size limited.)
ideally, want write int
size n
of array, , write n
times 64 bits of uint64
, , read similarly. can this?
coder.encodeobject(values, forkey: "v")
doesn't work.
class myobject: nscoding { private var values: [uint64] // … // mark: - nscoding required init(coder decoder: nscoder) { // ??? } func encodewithcoder(coder: nscoder) { // ??? } }
here possible solution encodes uint64
array array of bytes. inspired answers how serialize c array 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 unsafepointer<uint8>, pointing immutable data. let ptr = decoder.decodebytesforkey("values", returnedlength: &count) // if convert buffer pointer of appropriate type , count ... let buf = unsafebufferpointer<uint64>(start: unsafepointer(ptr), count: count/sizeof(uint64)) // ... array creation becomes easy. values = array(buf) } func encodewithcoder(coder: nscoder) { // encodes both number of bytes , 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 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 unsafepointer<uint8>?, pointing immutable data. if let ptr = decoder.decodebytes(forkey: "values", returnedlength: &count) { // if convert buffer pointer of appropriate type , count ... let numvalues = count / memorylayout<uint64>.stride ptr.withmemoryrebound(to: uint64.self, capacity: numvalues) { let buf = unsafebufferpointer<uint64>(start: unsafepointer($0), count: numvalues) // ... array creation becomes easy. values = array(buf) } } } public func encode(with coder: nscoder) { // encodes both number of bytes , 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]
Comments
Post a Comment