2015-09-16 2 views
19

Я ищу простейшие способы достижения разумной совместимости C в Swift, и мой текущий блок преобразует UnsafePointer<Int8> (который был const char *) в массив [Int8].Преобразование UnsafePointer с длиной в тип Swift Array

В настоящее время у меня есть наивный алгоритм, который может принимать 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), однако это не устраняет проблему самого цикла.

Я знаю this SO question, которая охватывает как конвертировать UnsafePointer<Int8> в String, однако String это другое животное полностью [T]. Есть ли удобный способ быстрого копирования байтов длины из UnsafePointer<T> в [T]? Я бы предпочел использовать чистые методы Swift, не проходя через NSData или аналогичный. Если этот алгоритм действительно единственный способ сделать это, я с удовольствием придерживаюсь этого.

ответ

30

Вы можете просто инициализировать 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.

+0

Приводит ли это утечка памяти? Я не могу найти никаких указаний на то, что 'UnsafeBufferPointer' освободит свою память. – Alexander

+0

@AMomchilov:' UnsafeBufferPointer' - это просто указатель, он не выделяет память, поэтому нет ничего свободного. Затем «Массив» управляется Свифт. –

+0

Да, но указатель, переданный в 'convert', должен быть освобожден, правильно? Это должно быть сделано явным, IMO – Alexander

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

Вы можете преобразовать данные строки в byts (Uint8)

Copy Extension и использовать его ..

+0

Это безумно полезно. Мой C <-> Быстрое волнение от взаимодействия просто тает. – dugla

+0

Приятно слышать, что ^^ –

Смежные вопросы