2015-09-16 7 views
19

Ich bin auf der Suche nach den einfachsten Möglichkeiten, um eine vernünftige C-Interoperabilität in Swift zu erreichen, und mein aktueller Block konvertiert ein UnsafePointer<Int8> (das war ein const char *) in ein [Int8] Array.Umwandlung eines UnsafePointer mit Länge in einen Swift Array Typ

Derzeit Ich habe einen naiven Algorithmus, der eine UnsafePointer und eine Anzahl von Bytes nehmen und wandelt es in ein Array, Element für Element:

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

Die Schleife selbst durch Verwendung arr.reserveCapacity(length) beschleunigt werden kann, Das beseitigt jedoch nicht das Problem der Schleife selbst.

Ich bin mir dessen bewusst this SO question, die beschreibt, wie UnsafePointer<Int8>-String zu konvertieren, aber String ist ein anderes Tier ganz [T]. Gibt es einen praktischen schnellen Weg, um Längenbytes von einem UnsafePointer<T> in einen [T] zu kopieren? Ich würde reine Swift-Methoden bevorzugen, ohne NSData oder ähnliches zu durchlaufen. Wenn der obige Algorithmus wirklich der einzige Weg ist, dies zu tun, bin ich glücklich, dabei zu bleiben.

Antwort

30

Sie können einfach eine Swift Array von einem UnsafeBufferPointer initialisieren:

func convert(length: Int, data: UnsafePointer<Int8>) -> [Int8] { 

    let buffer = UnsafeBufferPointer(start: data, count: length); 
    return Array(buffer) 
} 

Dieses eine Anordnung der benötigten Größe erzeugt und kopiert die Daten.

Oder als generische Funktion:

func convert<T>(count: Int, data: UnsafePointer<T>) -> [T] { 

    let buffer = UnsafeBufferPointer(start: data, count: count); 
    return Array(buffer) 
} 

wo length die Zahl der Artikel ist, dass der Zeiger auf.

Wenn Sie einen UInt8 Zeiger, sondern wollen eine [T] Array von der spitze zu Daten erstellen, dann ist dies eine mögliche Lösung:

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

wo length jetzt ist die Anzahl der Bytes. Beispiel:

let arr = convert(12, data: ptr, Float.self) 

würde eine Anordnung von 3 Float s aus dem 12 Bytes erzeugen, auf dem durch ptr.

+0

Verursacht dies ein Speicherleck? Ich kann keinen Hinweis darauf finden, dass 'UnsafeBufferPointer' seinen Speicher freigibt – Alexander

+0

@AMomchilov:' UnsafeBufferPointer' ist nur ein Zeiger, er reserviert keinen Speicher, also gibt es nichts zu befreien. Das 'Array' wird dann von Swift verwaltet. –

+0

Ja, aber der Zeiger, der in 'convert' übergeben wurde, muss freigegeben werden, oder? Das sollte explizit gemacht werden, 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 
    } 
} 

Sie können Zeilendaten Byts (Uint8) konvertieren

Copy-Erweiterung und verwenden Sie es ..

+0

Das ist wahnsinnig hilfreich. Mein C <-> Swift Interop Angst ist nur schmelzen. – dugla

+0

Schön das zu hören ^^ –

Verwandte Themen