Reputation: 133
I have a Swift struct of Int32, floats and data and I want to save this struct instance in a binary format - Can someone help me on how to write or save file in the binary format?
struct Another {
let imgCount: UInt32
let resetFlag: UInt32
let focalX: Float
let focalY: Float
let somedata: Data
}
Also the MemoryLayout<Another>.size
and MemoryLayout<Another>.stripe
is confusing.
Upvotes: 0
Views: 2301
Reputation: 236370
You will need to reserve the first 16 bytes (4 bytes for each numeric property because they are all 32 bits). The tail of the data will be used for the data property someData
which can be of any size:
struct Another {
// UInt32 - A 32-bit unsigned integer value type. You will need 4 bytes for each property
// 4 + 4 = 8 Bytes
let imgCount, resetFlag: UInt32
// Float - A single-precision, floating-point value type. Again 4 bytes for each property
// 4 + 4 = 8 Bytes
let focalX, focalY: Float
// the data can have any size this will be all bytes from index 16 until the end of the file
let someData: Data
}
To convert the numeric types to Data and back you can use the following helpers:
extension Numeric {
var data: Data {
var source = self
return Data(bytes: &source, count: MemoryLayout<Self>.size)
}
}
extension Data {
func object<T>() -> T { withUnsafeBytes { $0.load(as: T.self) } }
}
Now you just need to create a custom initializer to decode your data iterating over your data and set the correspond properties values.
extension Another {
init(_ data: Data) {
var startIndex = data.startIndex
var endIndex = startIndex.advanced(by: MemoryLayout<UInt32>.size)
let imgCountRange = startIndex..<endIndex
self.imgCount = data[imgCountRange].object()
startIndex = endIndex
endIndex = startIndex.advanced(by: MemoryLayout<UInt32>.size)
let resetFlagRange = startIndex..<endIndex
self.resetFlag = data[resetFlagRange].object()
startIndex = endIndex
endIndex = startIndex.advanced(by: MemoryLayout<Float>.size)
let focalXRange = startIndex..<endIndex
self.focalX = data[focalXRange].object()
startIndex = endIndex
endIndex = startIndex.advanced(by: MemoryLayout<Float>.size)
let focalYRange = startIndex..<endIndex
self.focalY = data[focalYRange].object()
self.someData = data[endIndex...]
}
}
To encode your structure will be much easier:
extension Another {
var data: Data {
return imgCount.data + resetFlag.data + focalX.data + focalY.data + someData
}
}
Testing:
let obj1 = Another(imgCount: 1, resetFlag: 2, focalX: 3.4, focalY: 5.6, someData: Data([0,1,2,3,4,5,6,7,8,9,10]))
let obj2 = Another(imgCount: 3, resetFlag: 4, focalX: 5.6, focalY: 7.8, someData: Data([10,11,12,13,14,15,16,17,18,19,20,21,22]))
let obj1Data = obj1.data
print(obj1Data) // 27 bytes
let obj1FromData = Another(obj1Data)
print(obj1FromData)
let obj2Data = obj2.data
print(obj2Data) // 29 bytes
let obj2FromData = Another(obj2Data)
print(obj2FromData)
This will print
27 bytes
Another(imgCount: 1, resetFlag: 2, focalX: 3.4, focalY: 5.6, someData: 11 bytes)
29 bytes
Another(imgCount: 3, resetFlag: 4, focalX: 5.6, focalY: 7.8, someData: 13 bytes)
Upvotes: 3