我该如何在Swift中使用UnsafeMutablePointer<UnsafeMutablePointer<Void>>引用?

11

我正在使用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.9,似乎合理。 第二个大小值显然是虚假的,然后它崩溃了,我进入了调试器。

indexes 0 0
indexes 0 3
0 0.929816
1 1.51296e-39
(lldb)
据我所知,互联网上没有人使用这个函数。 我找到的唯一参考资料是苹果的文档,其中仅提供了该函数的ObjC示例,而非Swift。

帮帮我!


1
叫我疯了,但既然这是一个指向指针的指针,你难道不应该取它的memory.memory来到达真正的东西吗? - matt
好的观点。切换到myptr.memory[i].size让我更接近了,但它仍然会偶尔崩溃。如果我设置大小,那么我可以看到一些但不是所有的粒子都在改变。而且那些改变的粒子会停滞不前,停止移动。这表明我正在破坏某些内存。而且我仍然不确定数据步幅是用来做什么的。文档说它应该是:“标识每个粒子数据条带中每个属性值的偏移量(以字节为单位)的数组。此数组中的偏移量顺序对应于addModifierForProperties调用中属性数组的顺序”。 - Josh Marinacci
我应该提到,在ObjC示例代码中使用了dataStride,但我看不出我如何在Swift版本中使用它。 - Josh Marinacci
我从未使用过这个API,所以我不知道。我会倾向于说:嘿,让我们仅在代码的这一部分中使用Objective-C。将其简化为先前解决的问题,你明白我的意思吗? :) - matt
2个回答

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吗???


你想改进一下你的回答,这样我就可以授予悬赏了吗?也许你已经解决了它 :) - Jiri Trecak

0

使用非常相似的 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问题和回答这里中有更多细节。

还有一些要点这里这里


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接