Как я могу работать с ссылкой UnsafeMutablePointer <UnsafeMutablePointer <Void>> от Swift?

Я создаю тестовое приложение, используя SceneKit SCNParticleSystem. Он имеет обратный вызов, который позволяет изменять свойства частиц на каждом фрейме. Подпись этого обратного вызова

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

Ссылка на сайт разработчика Apple - SCNParticleSystem_Class

Я не знаю, как получить доступ и изменить эту ссылку от Swift. Если бы это было C, это было бы **, что я мог бы разыменовать массив.

После некоторого futzing я дошел до этого:

..... 
           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.

Помогите мне!

Ответ 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 спросило и ответил на вопрос здесь

И пара gists здесь и здесь