将具有长度的 UnsafePointer 转换为 Swift 数组类型
Converting an UnsafePointer with length to a Swift Array type
我正在寻找在 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<Int8>
转换为 String
,但是 String
与 [T]
完全不同。是否有方便的 Swift 方法将 length 字节从 UnsafePointer<T>
复制到 [T]
?我更喜欢纯 Swift 方法,而不通过 NSData
或类似方法。如果上述算法真的是唯一的方法,我很乐意坚持下去。
您可以简单地从 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: [=12=], count: numItems)
}
return Array(buffer)
}
其中 length
现在是 字节数 。示例:
let arr = convert(12, data: ptr, Float.self)
将从 ptr
指向的 12 个字节创建一个 3 Float
的数组。
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)
复制扩展并使用它..
您还可以使用数组初始化函数:
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]
}
}
}
我正在寻找在 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<Int8>
转换为 String
,但是 String
与 [T]
完全不同。是否有方便的 Swift 方法将 length 字节从 UnsafePointer<T>
复制到 [T]
?我更喜欢纯 Swift 方法,而不通过 NSData
或类似方法。如果上述算法真的是唯一的方法,我很乐意坚持下去。
您可以简单地从 UnsafeBufferPointer
:
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: [=12=], count: numItems)
}
return Array(buffer)
}
其中 length
现在是 字节数 。示例:
let arr = convert(12, data: ptr, Float.self)
将从 ptr
指向的 12 个字节创建一个 3 Float
的数组。
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)
复制扩展并使用它..
您还可以使用数组初始化函数:
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]
}
}
}