2017-04-24 11 views
0

나는 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 입력을 사용하는 몇 가지 다른 방법은 무엇입니까?

감사합니다.

--- 편집 : 요청으로, 수정 후 내 코드 : 당신은 예를 들어, C의 기능에 약간의 문맥을 전달할 수 있습니다

보통
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) 

} 
+0

이것은 또한 도움이 될 수 있습니다 : [에만 FUNC 또는 문자 폐쇄 소요 함수의 콜백으로 인스턴스 메소드를 사용하는 방법 (http://stackoverflow.com/questions/33260808/how-to-use-instance-method-as-call-for-function-which-takes-only-func-or-litre)를 사용하는 것이 좋습니다. –

+0

@MartinR'UnsafeRawPointer (Unmanaged.passUnretained (self) .toOpaque())'하지만 여전히 같은 오류가 발생합니다. –

+0

클로저 내부에서'self'를 사용하면 안됩니다. 재구성해야합니다. 컨텍스트 포인터에서, 링크 된 응답에서'let mySelf = Unmanaged ...'를 참조하십시오. –

답변

0

:

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]) 

(테스트없이 작성)

+0

하지만 멋진 솔루션처럼 보입니다. 그렇다면 컨텍스트 변수에서'self'에 어떻게 접근 할 수 있습니까? –

+0

@WesleyPeeters 사실,'self'를 컨텍스트로 전달하거나 직접'struct'에 추가 할 수 있습니다. 또는'getSelf' 함수를'struct'에 추가 할 수 있습니다. 내 요점은 보통 당신이'자기 '를 전달할 필요가 없다는 것이 었습니다. 대신,'setSliderValue'처럼 내부에 이미 포장 된 함수/클로저를 전달할 수 있습니다. – Sulthan