You're looking for loadUnaligned(fromByteOffset:as:). But also, if you can provide a little more context about what you're trying to accomplish, there may be a better way to do it.
We are trying to get 4 bytes from the hash, starting at the given byte offset as calculated and initialize tH with that value. Hash is of Data, as returned by Data(bytes: macOut, count: hashLength)
We are getting this error on ios 16 ; ios 15 works fine.
This assumes the UInt32 is big endian. If it’s little endian, add a .reversed(). If it’s native endian, things get a bit trickier (-:
The advantage of this approach is that it avoids unsafe constructs. You’ll never get undefined behaviour. Either it’ll work, or it’ll return nil, or I’ve forgotten a precondition and it’ll trap.
extension Array where Element == UInt8 {
func loadUnaligned<T>(from offset: Index = 0, as: T.Type) -> T {
withUnsafeBufferPointer { buffer in
precondition(offset + MemoryLayout<T>.size <= buffer.count)
precondition(_isPOD(T.self))
return UnsafeRawBufferPointer(buffer).loadUnaligned(fromByteOffset: offset, as: T.self)
}
}
}
It is generally good to avoid unsafe APIs, but when there are significant benefits (as there can be in this case), it can be worthwhile.
Unsafe APIs do not check their preconditions at runtime in release builds -- but it is still possible to use them safely, and if the unchecked code is small and simple enough that you can reason about it and add those precondition checks yourself, you can still build safe APIs using them.
Calling a complex generic algorithm with no bounds checking is an easy path to UB, because it is difficult to reason about all of the preconditions that may be violated in all functions and called functions, and to maintain that assurance as the code evolves - but performing a single load is simple enough that we can create a safe version quite easily, in a little function that others can invoke without worrying about UB.