web-dev-qa-db-fra.com

Conversion d'un UnsafePointer de longueur en un Swift Array type

Je cherche les moyens les plus simples pour obtenir une interopérabilité C raisonnable dans Swift, et mon bloc actuel convertit un UnsafePointer<Int8> (Qui était un const char *), En un tableau [Int8] .

Actuellement, j'ai un algorithme naïf qui peut prendre un UnsafePointer et un certain nombre d'octets et le convertit en tableau, élément par élément:

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

La boucle elle-même peut être accélérée en utilisant arr.reserveCapacity(length), mais cela ne supprime pas le problème de la boucle elle-même.

Je connais cette SO question qui explique comment convertir UnsafePointer<Int8> En String, cependant String est une bête complètement différente de [T]. Existe-t-il une manière pratique Swift de copier des octets de longueur d'un UnsafePointer<T> dans un [T]? I Je préférerais les méthodes Swift, sans passer par NSData ou similaire. Si l'algorithme ci-dessus est vraiment la seule façon de le faire, je suis heureux de m'en tenir à cela.

27
Ephemera

Vous pouvez simplement initialiser un Swift Array à partir d'un UnsafeBufferPointer:

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

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

Cela crée un tableau de la taille requise et copie les données.

Ou comme fonction générique:

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

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

length est le nombre de items vers lequel pointe le pointeur.

Si tu as un UInt8 pointeur mais souhaitez créer un [T] tableau à partir des données pointées, voici une solution possible:

// 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 est maintenant le nombre de octets. Exemple:

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

créerait un tableau de 3 Floats à partir des 12 octets pointés par ptr.

42
Martin R
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
    }
}

Vous pouvez convertir des données de ligne en octets (Uint8)

Copiez l'extension et utilisez-la ..

1
tBug