【问题标题】:Access self from a C style pointer [duplicate]从 C 样式指针访问 self [重复]
【发布时间】:2017-04-24 13:17:35
【问题描述】:

我正在开发一个使用 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 输入?

谢谢。

--- 编辑: 如题,我修改后的代码:

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)

}

【问题讨论】:

  • @MartinR 尝试这样做:UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque()) 但是,我仍然遇到同样的错误
  • 你不能在闭包内使用self,你必须从上下文指针重建它,参见链接到答案中的let mySelf = Unmanaged ...
  • 我从来没有直接引用self,我使用了let mySelf = Unmanaged...,之后我尝试使用mySelf变量@MartinR
  • 您可以将修改后的代码添加到您的问题中吗?我相当确定它有效。

标签: swift macos cocoa midi coremidi


【解决方案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])

(未经测试编写)

【讨论】:

  • 似乎是一个很棒的解决方案,但是,我如何才能从上下文变量访问self
  • @WesleyPeeters 实际上,您可以将self 作为上下文传递,也可以直接将其添加到struct。或者您可以将函数getSelf 添加到struct。我的意思是,通常你不需要通过self。相反,您可以传递一个已经包含 self 的函数/闭包,就像我的 setSliderValue 所做的那样。
猜你喜欢
  • 1970-01-01
  • 2019-09-22
  • 2014-04-10
  • 2023-04-04
  • 2015-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多