Доступ к себе из указателя стиля C
Я работаю над приложением, которое использует оборудование MIDI. После некоторого дурачения на детской площадке с CoreMIDI я нашел, как получить входной MIDI-сигнал, поэтому я реализовал это:
func makeInputSource() {
var midiClient : MIDIClientRef = 0
var inPort : MIDIPortRef = 0
MIDIClientCreate("WobClient" as CFString, nil, nil, &midiClient)
MIDIInputPortCreate(midiClient, "WobClient_InPort" as CFString, {
(pktList: UnsafePointer<MIDIPacketList>, readProcRefCon: UnsafeMutableRawPointer?, srcConnRefCon: UnsafeMutableRawPointer?) in
let packetList : MIDIPacketList = pktList.pointee
var packet : MIDIPacket = packetList.packet
for _ in 1...packetList.numPackets {
let bytes = Mirror(reflecting: packet.data).children
var params : [UInt64] = []
var i = packet.length
for (_, attr) in bytes.enumerated() {
let string = String(format: "%02X ", attr.value as! UInt8)
params.append(UInt64(strtoul(string, nil, 16)))
i -= 1
if (i <= 0) {
break
}
}
packet = MIDIPacketNext(&packet).pointee
}
}, nil, &inPort)
MIDIPortConnectSource(inPort, self.source, &self.source)
}
Который работает как брелок для использования сигнала. Теперь я хочу использовать сигнал для редактирования значения NSSlider
Итак, естественно, я придумал следующее:
self.slider_one?.integerValue = params[2]
Однако, когда я пытаюсь это сделать, я получаю следующую ошибку:
A C function pointer cannot be formed from a closure that captures context
Так что мне интересно, есть ли способ получить доступ self
изнутри этого замыкания, или есть какой-то другой способ использовать MIDI-вход в Swift?
Благодарю.
--- Редактировать: Как и просили, мой код после модификации:
func makeInputSource() {
var midiClient : MIDIClientRef = 0
var inPort : MIDIPortRef = 0
var observer = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())
MIDIClientCreate("WobClient" as CFString, nil, nil, &midiClient)
MIDIInputPortCreate(midiClient, "WobClient_InPort" as CFString, {
(pktList: UnsafePointer<MIDIPacketList>, readProcRefCon: UnsafeMutableRawPointer?, srcConnRefCon: UnsafeMutableRawPointer?) in
let packetList : MIDIPacketList = pktList.pointee
var packet : MIDIPacket = packetList.packet
for _ in 1...packetList.numPackets {
let bytes = Mirror(reflecting: packet.data).children
var params : [UInt64] = []
var i = packet.length
for (_, attr) in bytes.enumerated() {
let string = String(format: "%02X ", attr.value as! UInt8)
params.append(UInt64(strtoul(string, nil, 16)))
i -= 1
if (i <= 0) {
break
}
}
let mySelf = Unmanaged<Wob>.fromOpaque(observer).takeUnretainedValue()
mySelf.slider_one?.integerValue = 25 // 25 is a test value
packet = MIDIPacketNext(&packet).pointee
}
}, &observer, &inPort)
MIDIPortConnectSource(inPort, self.source, &self.source)
}
1 ответ
Обычно вы можете передать некоторый контекст в функции C, например:
struct MyContext {
var setSliderValue: (Int) -> Void
}
var context = MyContext(setSliderValue: { sliderValue in
Dispatch.queue.async {
self.slider_one?.integerValue = sliderValue
}
))
затем передайте его вашей функции C:
MIDIInputPortCreate(midiClient, "WobClient_InPort" as CFString, { ... }, &context, &inPort)
и внутри вашей функции закрытия:
let readContext = readProcRefCon!.assumingMemoryBound(to: MyContext.self)
readContext.pointee.setSliderValue(params[2])
(написано без тестирования)