【问题标题】:How do I work with a UnsafeMutablePointer<UnsafeMutablePointer<Void>> reference from Swift?如何使用 Swift 的 UnsafeMutablePointer<UnsafeMutablePointer<Void>> 引用?
【发布时间】:2016-01-19 20:16:33
【问题描述】:

我正在使用 SceneKit 的 SCNParticleSystem 构建一个测试应用程序。它有一个回调,可让您修改每一帧上的粒子属性。这个回调的签名是

typealias SCNParticleModifierBlock = (UnsafeMutablePointer<UnsafeMutablePointer<Void>>, UnsafeMutablePointer<Int>, Int, Int, Float) -> Void

来自苹果开发者网站的参考 - SCNParticleSystem_Class

我不知道如何从 Swift 访问和修改此引用。如果这是 C,那将是一个 **,我可以像数组一样取消引用。

经过一番折腾,我已经做到了这一点:

..... 
           particleSystem?.addModifierForProperties([SCNParticlePropertySize], atStage: SCNParticleModifierStage.PostDynamics, withBlock: doit2)
}

struct Foos {
    var size:float_t
}
func doit2(data:UnsafeMutablePointer<UnsafeMutablePointer<Void>>, dataStride: UnsafeMutablePointer<Int>, start:Int, end:Int, deltaTime:Float) -> Void {
    let myptr = UnsafeMutablePointer<UnsafeMutablePointer<Foos>>(data)
    print("indexes",start,end)
    for i in 0 ..< end {
        print(i,myptr[i].memory.size)
    }
}¸

这适用于第一个粒子,但在第二个粒子上崩溃。第一次调用该函数时有 0 个粒子,因此它跳过了循环。第二次有三个粒子,所以它试图将它们打印出来。第一个尺寸值为 0.9,接缝合理。第二个大小值显然是伪造的,然后它崩溃了,我掉进了调试器。

indexes 0 0
indexes 0 3
0 0.929816
1 1.51296e-39
(lldb)

据我所知,互联网上没有人使用此功能。我找到的唯一参考资料是 Apple 的文档,它只提供了 ObjC 示例,而不是 Swift。

帮帮我!

【问题讨论】:

  • 叫我疯了,但既然这是一个指向指针的指针,你不应该用它的memory.memory 来达到真实的东西吗?
  • 好点。切换到myptr.memory[i].size 让我更接近,但它仍然时不时地崩溃。如果我设置了大小,那么我可以看到一些但不是所有的粒子都在变化。而那些确实发生变化的人会被卡住,他们会停止移动。这表明我正在破坏一些记忆。而且我仍然不确定 dataStride 的用途。文档说它应该是:“数组标识每个粒子的数据条带中每个属性值的偏移量(以字节为单位)。此数组中偏移量的顺序对应于 addModifierForProperties 调用中属性数组的顺序跨度>
  • 我应该提一下,在 ObjC 示例代码中使用了 dataStride,但我看不到在 Swift 版本中如何使用它。
  • 我从来没有使用过这个 API,所以我不知道。我很想说:嘿,让我们只在这一部分代码中使用 Objective-C。将其简化为先前已解决的问题,知道我的意思吗? :)

标签: ios swift scenekit


【解决方案1】:

例如:

var data = [[0.1, 0.2],[0.3, 0.4],[0.5, 0.6]]
let pData = UnsafeMutablePointer<UnsafeMutablePointer<Void>>(data)
// how to reconstruct the original data ??

// we need to know how much data we have
let count = data.count
// we need to know what type of data we have
let p2 = UnsafeMutablePointer<Array<Double>>(pData)
// access the data
for i in 0..<count {
    print((p2 + i).memory)
}
// [0.1, 0.2]
// [0.3, 0.4]
// [0.5, 0.6]

我认为在你的代码中,myptr 的声明是错误的

let myptr = UnsafeMutablePointer<UnsafeMutablePointer<Foos>>(data)

您的示例中的 dataStride.count 应为 1(属性数),其元素的值应为 float 的大小(属性的大小)。

也要小心!你的循环应该是这样的

for i in start..<end {
...
}

你确定开始是 0 吗???

【讨论】:

  • 您想改进您的答案以便我奖励赏金吗?也许你能解决它:)
【解决方案2】:

使用非常相似的 SCNParticleEventBlock,我在 Swift3 中将处理程序编写为

 ps.handle(SCNParticleEvent.birth, forProperties [SCNParticleSystem.ParticleProperty.color]) {
    (data:UnsafeMutablePointer<UnsafeMutableRawPointer>, dataStride:UnsafeMutablePointer<Int>, indicies:UnsafeMutablePointer<UInt32>?, count:Int) in

    for i in 0..<count {

        // get an UnsafeMutableRawPointer to the i-th rgba element in the data
        let colorsPointer:UnsafeMutableRawPointer = data[0] + dataStride[0] * i

        //  convert the UnsafeMutableRawPointer to a typed pointer by binding it to a type:
        let floatPtr = colorsPointer.bindMemory(to: Float.self, capacity: dataStride[0])
        // convert that to a an  UnsafeMutableBufferPointer
        var rgbaBuffer = UnsafeMutableBufferPointer(start: floatPtr, count: dataStride[0])
        // At this point, I could convert the buffer to an Array, but doing so copies the data into the array and any changes made in the array are not reflected in the original data.  UnsafeMutableBufferPointer are subscriptable, nice.
        //var rgbaArray = Array(rgbaBuffer)

        // about half the time, mess with the red and green components
        if(arc4random_uniform(2) == 1) {
            rgbaBuffer[0] = rgbaBuffer[1]
            rgbaBuffer[1] = 0
        }
    }
 }

在我的 SO 提问和回答的问题 here 中有更多细节

还有几个要点 herehere

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-15
    • 1970-01-01
    相关资源
    最近更新 更多