2015-09-16 8 views
19

Sto cercando i modi più semplici per ottenere un'interoperabilità C ragionevole in Swift e il mio blocco corrente sta convertendo un UnsafePointer<Int8> (che era un const char *) in un array [Int8].Conversione di un UnsafePointer di lunghezza con un tipo di array Swift

Attualmente, ho un algoritmo banale che può assumere un UnsafePointer e un numero di byte e lo converte in un array, elemento per elemento:

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

L'anello stesso può essere accelerato mediante arr.reserveCapacity(length), tuttavia ciò non rimuove il problema del loop stesso.

Sono consapevole di this SO question che copre come convertire UnsafePointer<Int8>-String, tuttavia String è una bestia diversa interamente alla [T]. Esiste un modo rapido per copiare i byte di lunghezza da uno UnsafePointer<T> in un [T]? Preferirei i metodi puri di Swift, senza passare attraverso NSData o simili. Se l'algoritmo di cui sopra è davvero l'unico modo per farlo, sono felice di attenervelo.

risposta

30

Si può semplicemente inizializzare una Swift Array da un UnsafeBufferPointer:

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

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

Questo crea un array di dimensioni necessarie e copia i dati.

O come una funzione generica:

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

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

dove length è il numero di elementi che punta il puntatore a.

Se si dispone di un puntatore UInt8 ma si desidera creare un array [T] dal la punta-ai dati, allora questa è una possibile soluzione:

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

dove length ora è il numero di byte. Esempio:

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

creerebbe un array di 3 Float s da 12 byte puntato da ptr.

+0

Questo causa una perdita di memoria? Non riesco a trovare alcuna indicazione che 'UnsafeBufferPointer' libererà la sua memoria – Alexander

+0

@AMomchilov:' UnsafeBufferPointer' è solo un puntatore, non alloca memoria, quindi non c'è nulla da liberare. "Array" è quindi gestito da Swift. –

+0

Sì, ma il puntatore passato in 'convert' deve essere liberato, giusto? Questo dovrebbe essere reso esplicito, 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 
    } 
} 

È possibile convertire i dati di riga per byts (uint8)

Copia di estensione e usarlo ..

+0

Questo è follemente utile. My C <-> L'ansia da interruzione rapida si sta sciogliendo. – dugla

+0

Bello sentire che ^^ –

Problemi correlati