swiftserializationstructnsdatanskeyedarchiver

Swift structs to NSData and back


I have a struct containing a struct and an NSObject that I want to serialize into an NSData object:

struct Packet {
  var name: String
  var index: Int
  var numberOfPackets: Int
  var data: NSData
}

var thePacket = Packet(name: name, index: i, numberOfPackets: numberOfPackets, data: packetData)

How do I best serialize the Packet into an NSData, and how do I best deserialize it?

Using

var bufferData = NSData(bytes: & thePacket, length: sizeof(Packet))

of only gives me the pointers of name and data. I was exploring NSKeyedArchiver, but then I'd have to make Packet an object, and I'd prefer to keep it a struct.

Cheers

Nik


Solution

  • Not really getting any feedback, this is the solution I ended up with:

    1. Make encode() and decode() functions for my struct
    2. Change Int to Int64 so the Int has the same size on 32-bit and 64-bit platforms
    3. Have an intermediate struct (ArchivedPacket) that has no String or Data, but only Int64

    Here is my code, I would be very grateful for your feedback, especially if there are less cumbersome ways to do this:

    public struct Packet {
        var name: String
        var index: Int64
        var numberOfPackets: Int64
        var data: NSData
    
        struct ArchivedPacket {
            var index : Int64
            var numberOfPackets : Int64
            var nameLength : Int64
            var dataLength : Int64
        }
    
        func archive() -> NSData {
    
            var archivedPacket = ArchivedPacket(index: Int64(self.index), numberOfPackets: Int64(self.numberOfPackets), nameLength: Int64(self.name.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)), dataLength: Int64(self.data.length))
    
            var metadata = NSData(
                bytes: &archivedPacket,
                length: sizeof(ArchivedPacket)
            )
    
            let archivedData = NSMutableData(data: metadata)
            archivedData.appendData(name.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!)
            archivedData.appendData(data)
    
            return archivedData
        }
    
        func unarchive(data: NSData!) -> Packet {
            var archivedPacket = ArchivedPacket(index: 0, numberOfPackets: 0, nameLength: 0, dataLength: 0)
            let archivedStructLength = sizeof(ArchivedPacket)
    
            let archivedData = data.subdataWithRange(NSMakeRange(0, archivedStructLength))
            archivedData.getBytes(&archivedPacket)
    
            let nameRange = NSMakeRange(archivedStructLength, Int(archivedPacket.nameLength))
            let dataRange = NSMakeRange(archivedStructLength + Int(archivedPacket.nameLength), Int(archivedPacket.dataLength))
    
            let nameData = data.subdataWithRange(nameRange)
            let name = NSString(data: nameData, encoding: NSUTF8StringEncoding) as! String
            let theData = data.subdataWithRange(dataRange)
    
            let packet = Packet(name: name, index: archivedPacket.index, numberOfPackets: archivedPacket.numberOfPackets, data: theData)
    
            return packet
        }
    }