Swift IO Binary

EDIT: TL; DR . In C family languages, you can represent arbitrary data (ints, floats, doubles, structs) as byte streams by casting and pack them into streams or buffers. And you can do the opposite to return the data. And, of course, you can change the bytes for correct fidelity.

Is this possible in idiomatic fast?

Now the original question:

If I were writing in C / C ++ / ObjC, I could pass the struct to unsigned char * and write my bytes to FILE * or memcpy them to the buffer. The same goes for ints, double, etc. I know that there are problems with the content, but this is for the iOS application, and I do not expect the rule of law to change in the near future for the platform. A system like Swift is not like it would allow this behavior (by distinguishing arbitrary data with unsigned 8-bit ints and passing an address), but I don't know.

I am learning Swift and would like an idiomatic way to write my data. Please note that my numbers are high and will ultimately be sent by wire, so it should be compact, so there are no text formats like JSON.

I could use NSKeyedArchiver, but I want to find out here. Also, I don't want to decommission the Android client at some point in the future, so simple binary coding seems to be where it is.

Any suggestions?

+6
source share
2 answers

As noted in using Swift with Cocoa and Objective-C , you can pass / assign an array of type Swift to the / variable parameter of the pointer type and vice versa to get a binary representation. This even works if you define your own struct types, as in C.

Here is an example - I use this code to pack 3D vertex data for the GPU (using SceneKit, OpenGL, etc.):

 struct Float3 { var x, y, z: GLfloat } struct Vertex { var position, normal: Float3 } var vertices: [Vertex] // initialization omitted for brevity let data = NSData(bytes: vertices, length: vertices.count * sizeof(Vertex)) 

Check this data, and you will see a pattern of 32 * 3 * 2 bits of IEEE 754 floating-point numbers (just like you could get access serialization using C struct via a pointer).

To go in another direction, you may need unsafeBitCast .

If you use this to save data, be sure to check or apply it.

+5
source

The type of format you are discussing is well understood using MessagePack . There are several early attempts to do this in Swift:

I would probably start with the yageek version. In particular, see how packaging is performed in data structures [Byte] . I would say that this is a pretty idiomatic Swift without losing endian control (which you shouldn't ignore, the chips are changing, and the numeric types give you via bigEndian ):

 extension Int32 : MsgPackMarshable{ public func msgpack_marshal() -> Array<Byte>{ let bigEndian: UInt32 = UInt32(self.bigEndian) return [0xce, Byte((bigEndian & 0xFF000000) >> 24), Byte((bigEndian & 0xFF0000) >> 16), Byte((bigEndian & 0xFF00) >> 8), Byte(bigEndian & 0x00FF)] } } 

It is also quite similar to how you write it in C or C ++, if you controlled byte order (which C and C ++ should always do, so the fact that they can break their bytes in memory does not proper implementations are trivial). I would probably drop Byte (which comes from Foundation) and use UInt8 (which is defined in the Swift core). But everything is in order. And, of course, it’s more idiomatic to say [UInt8] rather than Array<UInt8> .

However, as Zaf notes, NSKeyedArchiver is idiomatic for Swift. But this does not mean that MessagePack is not a good format for this kind of problem, and it is very portable.

+4
source

Source: https://habr.com/ru/post/973556/


All Articles