I have the following class:
class RawDataArray {
var data: NSData!
init(filePath: String) {
data = NSData(contentsOfFile: filePath)
}
func read<T>(offset: Int) -> T {
return UnsafePointer<T>(data.bytes + offset).memory
}
}
which I use in my iOS app to read from a binary file with a custom format. For example, to read an Int
at offset 5, I use:
let foo = rawData.read(5) as Int
This works in the simulator, on my iPad Air, and has passed the review for beta testing. However, my external testers have iPad 2s and 4s, and they are getting EXC_ARM_DA_ALIGN
errors.
I cannot change the structure of the input file. Is there any way to fix the read
function to make sure the objects are built from properly aligned memory locations?
Yes, reading unaligned data can fail on some architectures. A safe method is to copy the bytes into a (properly aligned) variable.
So the first idea would be to write a generic function:
func read<T>(offset: Int) -> T {
var value : T
memcpy(&value, data.bytes + offset, UInt(sizeof(T)))
return value
}
However, this does not compile, because the variable value
must be initialized before being used, and there is no default
constructor that can be used to initialize a complete generic
variable.
If we restrict the method to types which can be initialized with 0
then we get this:
func read<T : IntegerLiteralConvertible>(offset: Int) -> T {
var value : T = 0
memcpy(&value, data.bytes + offset, UInt(sizeof(T)))
return value
}
This works for all integer and floating point types.
For the general case, one could use the idea from https://stackoverflow.com/a/24335355/1187415:
func read<T>(offset: Int) -> T {
// Allocate space:
let ptr = UnsafeMutablePointer<T>.alloc(1)
// Copy data:
memcpy(ptr, data.bytes + offset, UInt(sizeof(T)))
// Retrieve the value as a new variable:
var item = ptr.move()
// Free the allocated space
ptr.dealloc(1)
return item
}
Swift allows to overload functions with different return types, therefore you can actually define both methods, and the compiler will automatically choose the more restrictive one.