从C风格指针访问自我
我正在研究利用MIDI设备的应用程序。与CoreMIDI操场一些打打闹闹之后,我发现如何让MIDI输入信号,所以我实现了这一点:从C风格指针访问自我
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输入快捷一些其他的方式?
谢谢。
---编辑: 至于问,修改后我的代码:
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)
}
通常你可以通过一些方面为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])
(书面未经测试)
看起来像一个很棒的解决方案,但是,我将如何能够从上下文变量访问'self'? –
@WesleyPeeters实际上,您可以将'self'作为上下文,或者直接将其添加到'struct'中。或者你可以在'struct'中添加一个'getSelf'函数。我的观点是,通常你不需要通过“自我”。相反,你可以传递一个已经包装了'self'的函数/闭包,就像我的'setSliderValue'一样。 – Sulthan
这也可能是有益的:如何使用实例方法作为回调函数,只需FUNC或立即关闭(http://*.com/questions/33260808 /如何使用的实例-方法-AS-回调换功能,其通吃仅-FUNC - 或亮)。 –
@MartinR试图这样做:'UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())'然而,我仍然得到相同的错误 –
你不能在闭包内使用'self',你必须重构它从上下文指针中,请参阅链接到的答案中的let mySelf = Unmanaged ...。 –