Using Swift CFunctionPointer to pass a callback to CoreMIDI API

前端 未结 2 2014
南旧
南旧 2020-11-30 08:51

It may be that this is actually not possible currently, which would be unfortunate. I\'m trying to call the CoreMIDI API to set up a MIDI input. This is what I\'m trying to

相关标签:
2条回答
  • 2020-11-30 09:32

    Swift 1.x (Old Way)

    There's a way to do that - Objective-C Runtime is the trick.

    import CoreMIDI
    
    let block : @objc_block
    (UnsafePointer<MIDIPacketList>,
    UnsafeMutablePointer<Void>,
    UnsafeMutablePointer<Void>) -> Void =
    { (pktlist,readProcRefCon,srcConnRefCon) in
    
        //Your code goes here...
    }
    
    let imp : COpaquePointer =
        imp_implementationWithBlock(unsafeBitCast(block, AnyObject.self))
    
    let callback : MIDIReadProc = unsafeBitCast(imp, MIDIReadProc.self)
    

    Works with CoreFoundation callbacks. Should work for CoreMIDI too.


    Swift 2.x (New Way)

    In Swift 2 the process becomes "less hacky" (and slightly more readable).

    import CoreMIDI
    
    let callback : @convention(c) (pktlist : UnsafePointer<MIDIPacketList>,
                                   readProcRefCon : UnsafeMutablePointer<Void>,
                                   srcConnRefCon : UnsafeMutablePointer<Void>) -> Void =
    
    { (pktlist, readProcRefCon, srcConRefCon) in
    
    }
    
    let usableCallback = unsafeBitCast(callback, MIDIReadProc.self)
    
    0 讨论(0)
  • 2020-11-30 09:47

    In Swift 2.0 (as part of Xcode 7), C APIs that deal in function pointers use function types that are annotated @convention(c). You can pass any Swift function, method, or closure as a @convention(c) function type — but only if that closure conforms to C conventions... e.g. it can't capture state from its surrounding scope.

    For details, see Type Attributes in The Swift Programming Language.


    As for what's in Xcode 6: Swift 1.x doesn't have a way to convert a Swift function or closure to a C function pointer -- the sole use of the CFunctionPointer type is to pass function pointers imported from (Obj)C APIs to other (Obj)C APIs.

    You can declare a function pointer in C code that you expose to Swift via your project's bridging header, then use Swift to pass that to CoreMIDI. But since you're going to be reaching across a bridge anyway, you might instead think about which parts of your project are best to keep in C and what the best interface is from those parts to your Swift code is.

    0 讨论(0)
提交回复
热议问题