32

我正在寻找在 Swift 中实现合理的 C 互操作性的最简单方法,而我当前的块正在将 a UnsafePointer<Int8>(它是 a 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 question涵盖了如何转换UnsafePointer<Int8>String,但是String完全不同于[T]. 是否有一种方便的 Swift 方法将长度字节从 a 复制UnsafePointer<T>到 a 中[T]?我更喜欢纯 Swift 方法,而不是通过NSData或类似的方法。如果上述算法真的是唯一的方法,我很乐意坚持下去。

4

3 回答 3

48

你可以简单地Array从一个 Swift 初始化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)

Float将从 3指向的 12 个字节创建一个数组ptr

于 2015-09-16T12:19:07.423 回答
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)

复制扩展并使用它..

于 2016-09-01T12:06:40.650 回答
0

您还可以使用数组初始化函数:

init(unsafeUninitializedCapacity: Int, initializingWith initializer: (inout UnsafeMutableBufferPointer<Element>, inout Int) throws -> Void) rethrows

如果需要,首先将 unsafeRawPointer 转换为 unsafePointer 然后将指针转换为缓冲区指针,最后将缓冲区指针转换为数组。

例如,假设您有一个 unsafeRawPointer ( dataPtr) 及其大小 ( dataSize)

let numberOfItems = dataSize / MemoryLayout<MyClass>.stride

let myArray = dataPtr.withMemoryRebound(to: MyClass.self,
                                        capacity: numberOfItems) { typedPtr in
    // Convert pointer to buffer pointer to access buffer via indices
    let bufferPointer = UnsafeBufferPointer(start: typedPtr, count: numberOfItems)
    // Construct array
    return [MyClass](unsafeUninitializedCapacity: numberOfItems) { arrayBuffer, count in
        count = numberOfItems
        for i in 0..<count {
            arrayBuffer[i] = bufferPointer[i]
        }
    }
}
于 2020-12-29T12:34:08.610 回答