Преобразование UnsafePointer с длиной в тип Swift Array
Я ищу простейшие способы достижения разумной совместимости С в Swift, и мой текущий блок преобразует UnsafePointer<Int8>
(который был const char *
) в массив [Int8]
.
В настоящее время у меня есть наивный алгоритм, который может принимать UnsafePointer
и количество байтов и преобразовывать его в массив, элемент за элементом:
func convert(length: Int, data: UnsafePointer<Int8>) {
let buffer = UnsafeBufferPointer(start: data, count: length);
var arr: [Int8] = [Int8]()
for (var i = 0; i < length; i++) {
arr.append(buffer[i])
}
}
Сам цикл можно ускорить, используя arr.reserveCapacity(length)
, однако это не устраняет проблему самого цикла.
Я знаю этот вопрос SO, в котором описывается, как преобразовать UnsafePointer<Int8>
в String
, однако String
является другим зверьком целиком до [T]
. Есть ли удобный способ быстрого копирования байтов длины из UnsafePointer<T>
в [T]
? Я бы предпочел использовать чистые методы Swift, не проходя через NSData
или подобное. Если этот алгоритм действительно единственный способ сделать это, я с удовольствием придерживаюсь этого.
Ответы
Ответ 1
Вы можете просто инициализировать Swift Array
с помощью UnsafeBufferPointer
:
func convert(length: Int, data: UnsafePointer<Int8>) -> [Int8] {
let buffer = UnsafeBufferPointer(start: data, count: length);
return Array(buffer)
}
Создает массив необходимого размера и копирует данные.
Или как общая функция:
func convert<T>(count: Int, data: UnsafePointer<T>) -> [T] {
let buffer = UnsafeBufferPointer(start: data, count: count);
return Array(buffer)
}
где length
- количество элементов, на которые указывает указатель.
Если у вас есть указатель UInt8
, но вы хотите создать массив [T]
из
заостренные данные, то это возможное решение:
// Swift 2:
func convert<T>(length: Int, data: UnsafePointer<UInt8>, _: T.Type) -> [T] {
let buffer = UnsafeBufferPointer<T>(start: UnsafePointer(data), count: length/strideof(T));
return Array(buffer)
}
// Swift 3:
func convert<T>(length: Int, data: UnsafePointer<UInt8>, _: T.Type) -> [T] {
let numItems = length/MemoryLayout<T>.stride
let buffer = data.withMemoryRebound(to: T.self, capacity: numItems) {
UnsafeBufferPointer(start: $0, count: numItems)
}
return Array(buffer)
}
где length
теперь - количество байтов. Пример:
let arr = convert(12, data: ptr, Float.self)
создаст массив из 3 Float
из 12 байт, на которые указывает ptr
.
Ответ 2
extension NSData {
public func convertToBytes() -> [UInt8] {
let count = self.length / sizeof(UInt8)
var bytesArray = [UInt8](count: count, repeatedValue: 0)
self.getBytes(&bytesArray, length:count * sizeof(UInt8))
return bytesArray
}
}
Вы можете преобразовать данные строк в байты (Uint8)
Скопируйте расширение и используйте его.