Using Structs (Bytes) with Swift - Struct to Nsdata and Nsdata to Struct

Using Structs (Bytes) with SWIFT - Struct to NSData and NSData to Struct

Change Byte! to Byte.

Otherwise you are creating struct holding Optional<Byte> which is larger than one byte because in addition to hold a byte, it need extra byte to indicate if it is nil

Note: This may still not working as you may need something like __attribute__((packed)) to tell compiler how to deal with alignment. AFAIK, it is not available in Swift.

Using Structs (includes byte Array) with SWIFT - Struct to NSData and NSData to Struct

var Message: [Byte] declares a variable of the type struct Array:

struct Array<T> : MutableCollectionType, Sliceable {

/// The type of element stored by this `Array`
typealias Element = T

/// Always zero, which is the index of the first element when non-empty.
var startIndex: Int { get }

/// A "past-the-end" element index; the successor of the last valid
/// subscript argument.
var endIndex: Int { get }
subscript (index: Int) -> T

// ... and much more ...
}

so this is not just a "C array" of bytes. The actual storage is opaque and only
accessible through methods and properties.

You can define a tuple of fixed size:

struct exampleStruct {
var ModelNumber: Byte
var MajorVersion: Byte
var MinorVersion: Byte
var Revision: Byte
var Message: (Byte, Byte, Byte, Byte, Byte)
}

var myStruct = exampleStruct (
ModelNumber: 1,
MajorVersion: 2,
MinorVersion: 3,
Revision: 4,
Message: (0x48, 0x45, 0x4C, 0x4C, 0x4F) // HELLO
)
var data = NSData(
bytes: &myStruct,
length: sizeof(exampleStruct)
)

println(data) // <01020304 48454c4c 4f>

However, I don't think that Swift makes any guarantees about the binary representation
of its structures, so this may break in the future.

Swift structs to NSData and back

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

Structs to NSData to Structs?

// make a NSData object
NSData *myData = [NSData dataWithBytes:&myPacketJoin length:sizeof(myPacketJoin)];

// make a new PacketJoin
PacketJoin newJoin;
[myData getBytes:&newJoin length:sizeof(newJoin)];

How to convert NSData to struct accurately

How the compiler lays out the individual fields of a struct in memory is implementation dependent. Usually the compiler has to add padding to properly align the fields and it might even reorder them (by grouping fields of the same size) to reduce the required padding and the overall size of the struct.

You can turn this behavior off using __attribute__((packed)):

typedef struct __attribute__((packed)) {
UInt8 cmd;
UInt16 index;
UInt32 timeStamp;
UInt16 steps;// 步数
UInt16 calories;// 卡路里
UInt16 distance;// 距离,单位m
UInt16 sleep;// 睡眠
UInt16 duration;// 运动时长,单位minute
} D2MHistoryDataPort;

How to Covert struct with an Array of string to NSData and vice versa Swift

Based on this answer:
Swift structs to NSData and back
I wrote this solution:

struct MessageRandomWords {
let message = MessageType.kMessageTypeRandomWords
var data : NSData?
var name: String

struct ArchivedPacket {
let message = MessageType.kMessageTypeRandomWords
var dataLength : Int64
var nameLength : Int64
}

func archive() -> NSData {
var archivedPack = ArchivedPacket(dataLength: Int64(self.data!.length), nameLength: Int64(self.name.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)))
var metaData = NSData(bytes: &archivedPack, length: sizeof(ArchivedPacket))
let archiveData = NSMutableData(data: metaData)
archiveData.appendData(name.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!)
archiveData.appendData(data!)
return archiveData
}

static func unarchive(data : NSData!) -> MessageRandomWords {
var archivedPacket = ArchivedPacket(dataLength: 0, nameLength: 0)
let archivedStructLength = sizeof(ArchivedPacket) //lenght of the struct

//Get the data tha will form our archived Packet
let archivedData = data.subdataWithRange(NSMakeRange(0, archivedStructLength))
//save the data taht form the archivedPacket inside the archivedPacket
archivedData.getBytes(&archivedPacket, length: archivedStructLength)
//get the range of data that contains the name
let nameRange = NSMakeRange(archivedStructLength, Int(archivedPacket.nameLength))
//get the range of the data that contains the data
let dataRange = NSMakeRange(archivedStructLength + Int(archivedPacket.nameLength), Int(archivedPacket.dataLength))
//get the data that rappresent the name
let nameData = data.subdataWithRange(nameRange)
//Get the name frome the data
let name = NSString(data: nameData, encoding: NSUTF8StringEncoding) as! String
// Geth the data
let theData = data.subdataWithRange(dataRange)

//Create the struct
let messageRndm = MessageRandomWords(data: theData, name: name)
return messageRndm
}

}

If you create the struct as showed, you can send your array of string by encode it as NSData and then decode it when received.

You can find the full working example on GitHub

If you have some better solutions please leave some feedback

Serialization of Structs to NSData in Swift

I've been looking at a serialization solution for Swift too. Instead of inventing your own protocol, take a look at RawRepresentable. It is more generic than what you are doing here in that it isn't tied to NSData. You could serialize to anything as long as your type specifies it in the RawValue type alias.

Serialization of Structs to NSData in Swift

I've been looking at a serialization solution for Swift too. Instead of inventing your own protocol, take a look at RawRepresentable. It is more generic than what you are doing here in that it isn't tied to NSData. You could serialize to anything as long as your type specifies it in the RawValue type alias.



Related Topics



Leave a reply



Submit