【问题标题】:Converting an UnsafePointer with length to a Swift Array type将具有长度的 UnsafePointer 转换为 Swift 数组类型
【发布时间】:2015-12-12 22:40:52
【问题描述】:

我正在寻找在 Swift 中实现合理的 C 互操作性的最简单方法,而我当前的块是将 UnsafePointer<Int8>(原为 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) 可以加速循环本身,但这并不能消除循环本身的问题。

我知道this SO question 介绍了如何将UnsafePointer&lt;Int8&gt; 转换为String,但是String[T] 完全不同。是否有一种方便的 Swift 方法将长度字节从 UnsafePointer&lt;T&gt; 复制到 [T] 中?我更喜欢纯 Swift 方法,而不通过 NSData 或类似方法。如果上述算法真的是唯一的方法,我很乐意坚持下去。

【问题讨论】:

    标签: c arrays swift unsafe-pointers


    【解决方案1】:

    你也可以使用数组初始化函数:

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

    【讨论】:

      【解决方案2】:

      您可以简单地从 UnsafeBufferPointer 初始化 Swift Array

      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)
      

      将从ptr 指向的12 个字节创建一个包含3 个Floats 的数组。

      【讨论】:

      • 这会导致内存泄漏吗?我找不到任何迹象表明UnsafeBufferPointer 将释放其内存
      • @AMomchilov: UnsafeBufferPointer 只是一个指针,它不分配内存,所以没有什么可以释放的。 Array 然后由 Swift 管理。
      • 是的,但是传递给convert 的指针必须被释放,对吧?这应该明确,IMO
      • @AMomchilov:你是对的,如果内存已经分配,​​那么它最终必须被释放。但是我们不知道那个指针来自哪里,它可能指向静态内存。在我看来,这与convert 函数无关。
      • 在 Swift 3 中,let buffer 行应该是 let buffer = data.withMemoryRebound(to: T.self, capacity: 1) {UnsafeBufferPointer(start: $0, count: length/MemoryLayout&lt;T&gt;.stride)}
      【解决方案3】:
      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)

      复制扩展并使用它..

      【讨论】:

      • 这非常有用。我的 C Swift 互操作焦虑正在消失。
      • 很高兴听到这个消息^^
      猜你喜欢
      • 1970-01-01
      • 2018-05-18
      • 1970-01-01
      • 1970-01-01
      • 2021-10-02
      • 1970-01-01
      • 2016-07-18
      • 2017-06-10
      • 1970-01-01
      相关资源
      最近更新 更多