Как преобразовать UInt16 в UInt8 в Swift 3?

Я хочу преобразовать массив UInt16 в массив UInt8, но получаю следующее сообщение об ошибке:

'init' недоступен: используйте 'withMemoryRebound(to:capacity:_)' для временного просмотра памяти как другого типа, совместимого с макетом.

Код:

    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))
    }

person Johan Tingbacke    schedule 04.06.2017    source источник


Ответы (2)


Как указано в сообщении об ошибке, вы должны использовать withMemoryRebound() для переинтерпретации указателя на UInt16 как указателя на 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)))
    }
}

Замыкания вызываются с помощью указателей ($0), которые действительны только в течение времени жизни замыкания и не должны передаваться наружу для последующего использования. Вот почему Array создается и используется как возвращаемое значение.

Однако есть более простое решение:

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

Объяснение: withUnsafeBytes вызывает замыкание с UnsafeRawBufferPointer для хранения переменной bigEndian. Поскольку UnsafeRawBufferPointer является Sequence из UInt8, массив может быть создан из массива с Array($0).

person Martin R    schedule 04.06.2017

Вы можете расширить числовой протокол и создать свойство данных следующим образом:

Swift 4 или новее

extension Numeric {
    var data: Data {
        var source = self
        return Data(bytes: &source, count: MemoryLayout<Self>.size)
    }
}

Поскольку данные Swift 3 соответствуют RandomAccessCollection, вы можете просто создать массив байтов из ваших данных UInt16 bigEndian:

extension Data {
    var array: [UInt8] { return Array(self) }
}

let lenghtByte = UInt16(8)
let bytePtr = lenghtByte.bigEndian.data.array   // [0, 8]
person Leo Dabus    schedule 04.06.2017