Search code examples
swifttype-conversionuint16uint8array

How to convert UInt16 to UInt8 in Swift 3?


I want to convert UInt16 to UInt8 array, but am getting the following error message:

'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.

The code:

    let statusByte: UInt8 = UInt8(status)
    let lenghtByte: UInt16 = UInt16(passwordBytes.count)

    var bigEndian = lenghtByte.bigEndian

    let bytePtr = withUnsafePointer(to: &bigEndian) {
        UnsafeBufferPointer<UInt8>(start: UnsafePointer($0), count: MemoryLayout.size(ofValue: bigEndian))
    }

Solution

  • As the error message indicates, you have to use withMemoryRebound() to reinterpret the pointer to UInt16 as a pointer to UInt8:

    let bytes = withUnsafePointer(to: &bigEndian) {
        $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: bigEndian)) {
            Array(UnsafeBufferPointer(start: $0, count: MemoryLayout.size(ofValue: bigEndian)))
        }
    }
    

    The closures are invoked with pointers ($0) which are only valid for the lifetime of the closure and must not be passed to the outside for later use. That's why an Array is created and used as return value.

    There is a simpler solution however:

    let bytes = withUnsafeBytes(of: &bigEndian) { Array($0) }
    

    Explanation: withUnsafeBytes invokes the closure with a UnsafeRawBufferPointer to the storage of the bigEndian variable. Since UnsafeRawBufferPointer is a Sequence of UInt8, an array can be created from that with Array($0).