如何使用 UnsafeMutableRawPointer 填充数组?
Posted
技术标签:
【中文标题】如何使用 UnsafeMutableRawPointer 填充数组?【英文标题】:How to use UnsafeMutableRawPointer to fill an array? 【发布时间】:2017-05-25 06:39:08 【问题描述】:我有一个金属纹理,我想通过将其设置为 float4 数组来从 Swift 访问它的数据(这样我就可以访问每个像素的 4 个颜色分量)。
我发现MTLTexture
这个方法:
getBytes(UnsafeMutableRawPointer, bytesPerRow: Int, bytesPerImage: Int, from: MTLRegion, mipmapLevel: Int, slice: Int)
我完全不知道如何使用 UnsafeMutableRawPointer,它是如何工作的,以及如何将数据返回到一个简单的 Swift 数组中。
我的第一次尝试是创建一个指针并分配足够的空间,但我什至不知道我是否应该这样做:
var pointer = UnsafeMutableRawPointer.allocate(bytes: myTextureSizeInBytes, alignedTo: 0)
然后我完全不知道如何将这些数据恢复到标准的 Swift 数组中......
谢谢。
【问题讨论】:
【参考方案1】:首先,假设您有一个UnsafeRawPointer
和一个长度:
let ptr: UnsafeRawPointer = ...
let length: Int = ...
现在您想将其转换为 [float4]
。首先,您可以通过将UnsafeRawPointer
绑定到类型来将其转换为类型化指针:
let float4Ptr = ptr.bindMemory(to: float4.self, capacity: length)
现在您可以将其转换为类型化缓冲区指针:
let float4Buffer = UnsafeBufferPointer(start: float4Ptr, count: length)
而且由于缓冲区是一个集合,你可以用它来初始化一个数组:
let output = Array(float4Buffer)
有关使用UnsafeRawPointer
的更多信息,请参阅SE-0138、SE-0107 和UnsafeRawPointer Migration Guide。
【讨论】:
非常感谢您的回答!获得 UInt8 数组后,如何将其转换为所需的类型?例如,如果我想要一个 float4 数组,我应该怎么做? 对不起;我错过了[float4]
的请求。我会更新的。
一定要检查马丁的回答;对于您的特定用例,它可能会更好。
哪些(如果有)步骤会导致复制源数据? Array
初始化器?
是的。从集合中初始化数组会复制集合。【参考方案2】:
另一种选择是创建一个适当大小的数组 并将底层存储的地址传递给函数:
var pixelData = Array(repeating: float4(), count: myTextureSizeInFloat4)
pixelData.withUnsafeMutableBytes
texture.getBytes($0.baseAddress!, ...)
在闭包内部,$0
是 UnsafeMutableRawBufferPointer
将数组存储表示为字节的集合,以及
$0.baseAddress
是指向第一个字节的指针。
【讨论】:
同意对于所描述的用例,这是更好的解决方案。我没有关注如何调用getBytes
。
感谢您的回答!为什么我们可以使用 UnsafeMutableRawBufferPointer
而 getBytes 除了 UnsafeMutableRawPointer
?
@TrevörAnneDenise: $0.baseAddress!
是UnsafeMutableRawPointer
。
@MartinR 哦,好吧!谢谢 !我现在正在尝试! ?
@TrevörAnneDenise:缓冲区指针描述了整个缓冲区,它本质上是指向第一个元素和长度的指针。它也是一个集合,因此您可以例如迭代for byte in myBufferPointer ...
。【参考方案3】:
详情
Xcode 11.2.1 (11B500)、Swift 5.1解决方案
extension UnsafeMutableRawPointer
func toArray<T>(to type: T.Type, capacity count: Int) -> [T]
let pointer = bindMemory(to: type, capacity: count)
return Array(UnsafeBufferPointer(start: pointer, count: count))
用法
var array = [1,2,3,4,5]
let ponter = UnsafeMutableRawPointer(mutating: array)
print(ponter.toArray(to: Int.self, capacity: array.count))
【讨论】:
【参考方案4】:补充@VasilyBodnarchuk 的回答:
extension UnsafeMutableRawPointer
func toArray<T>(to type: T.Type, capacity count: Int) -> [T]
return Array(UnsafeBufferPointer(start: bindMemory(to: type, capacity: count), count: count))
【讨论】:
【参考方案5】:这是一个将文字 UInt8 数组转换为 UnsafeMutableRawPointer 并返回到 UInt32 数组的 Swift 4 示例
static func unsafePointerTest()
//let a : [UInt8] = [0,0,0,4,0,0,0,8,0,0,0,12]
let a : [UInt8] = [0x04, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00] //little endian
//0xFF, 0xF0, 0xF0, 0x12] //317780223 = 12F0F0FF
let b:UnsafeMutableRawPointer = UnsafeMutableRawPointer(mutating:a)
let bTypedPtr = b.bindMemory(to: UInt32.self, capacity: a.count/4)
let UInt32Buffer = UnsafeBufferPointer(start: bTypedPtr, count: a.count/4)
let output = Array(UInt32Buffer)
print(output)
【讨论】:
以上是关于如何使用 UnsafeMutableRawPointer 填充数组?的主要内容,如果未能解决你的问题,请参考以下文章
如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]
如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?