【问题标题】:Swift 2 to swift 3 conversion Midi InputSwift 2 到 Swift 3 转换 Midi Input
【发布时间】:2016-07-08 03:09:43
【问题描述】:

我希望有人可以帮助我使用 Xcode 8 和 swift 3 我有一个操场文件 Xcode 7 swift 2,其中涉及 Midi Input 的 Midi 回调,在 7 中一切正常

我尝试转换为 8,但它带来了有关内存的错误和一些我认为不严重的名称更改我还使用 PlaygroundSupport 重新定义了无限循环 但是我无法克服的错误涉及 MyMIDIReadProc 在

MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);

错误说 无法将类型“(pktList:UnsafePointer,readProcRefCon:UnsafeMutablePointer,srcConnRefCon:UnsafeMutablePointer)-> Void”的值转换为预期的参数类型“MIDIReadProc”(又名“@convention(c)(UnsafePointer,Optional>,Optional>)->( )')

我的理解是它需要插入一些描述的@convention(c) 包装器。我认为我走在正确的轨道上,因为你可以包装一个函数,但我对把它放在哪里的了解已经用完了。我再次希望有人可以提供建议

感谢阅读 因为我是自学的,所以对任何不好的语言表示歉意

这是原始的 Xcode 7 代码

            import Cocoa
            import CoreMIDI
            import XCPlayground

            func getDisplayName(obj: MIDIObjectRef) -> String
            {
                var param: Unmanaged<CFString>?
                var name: String = "Error";

                let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, &param)
                if err == OSStatus(noErr)
                {
                    name =  param!.takeRetainedValue() as String
                }

                return name;
            }

            func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
                readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
            {
                let packetList:MIDIPacketList = pktList.memory;
                let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(COpaquePointer(srcConnRefCon)).memory;
                print("MIDI Received From Source: \(getDisplayName(srcRef))");

                var packet:MIDIPacket = packetList.packet;
                for _ in 1...packetList.numPackets
                {
                    let bytes = Mirror(reflecting: packet.data).children;
                    var dumpStr = "";
                    // bytes mirror contains all the zero values in the ridiulous packet data tuple
                    // so use the packet length to iterate.
                    var i = packet.length;
                    for (_, attr) in bytes.enumerate()
                    {
                         dumpStr += String(format:"$%02X ", attr.value as! UInt8);
                        --i;
                        if (i <= 0)
                        {
                           break;
                        }
                    }

                    print(dumpStr)
                    packet = MIDIPacketNext(&packet).memory;
                }
            }

            var midiClient: MIDIClientRef = 0;
            var inPort:MIDIPortRef = 0;
            var src:MIDIEndpointRef = MIDIGetSource(0);

            MIDIClientCreate("MidiTestClient", nil, nil, &midiClient);
            MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);

            MIDIPortConnectSource(inPort, src, &src);

            // Keep playground running
            XCPlaygroundPage.currentPage.needsIndefiniteExecution = true;

这是转换后的 Xcode 8 代码

            var str = "Hello, playground"
            import Cocoa
            import CoreMIDI
            import XCPlayground
            import PlaygroundSupport


             func getDisplayName(obj: MIDIObjectRef) -> String
             {
             var param: Unmanaged<CFString>?
             var name: String = "Error";

             let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, &param)
             if err == OSStatus(noErr)
             {
             name =  param!.takeRetainedValue() as String
             }

             return name;
             }


            func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
                                readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
             {


             let packetList:MIDIPacketList = pktList.pointee;

             let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(OpaquePointer(srcConnRefCon)).pointee;
             print("MIDI Received From Source: \(getDisplayName(obj: srcRef))");

             var packet:MIDIPacket = packetList.packet;
             for _ in 1...packetList.numPackets
             {
             let bytes = Mirror(reflecting: packet.data).children;
             var dumpStr = "";

             var i = packet.length;
             for (_, attr) in bytes.enumerated()
             {
             dumpStr += String(format:"$%02X ", attr.value as! UInt8);
             i -= 1;
             if (i <= 0)
             {
             break;
             }

             }

             print(dumpStr)
             packet = MIDIPacketNext(&packet).pointee;
             }
             }

            var midiClient: MIDIClientRef = 0;
             var inPort:MIDIPortRef = 0;
             var src:MIDIEndpointRef = MIDIGetSource(0);

             MIDIClientCreate("MidiTestClient", nil, nil, &midiClient);

             MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);

            MIDIPortConnectSource(inPort, src, &src);


             PlaygroundPage.current.needsIndefiniteExecution = true

【问题讨论】:

    标签: xcode swift midi swift-playground swift3


    【解决方案1】:

    指针类型在 Swift 3 中发生了巨大的变化。许多基于 C 的 API 的签名也发生了相应的变化。

    手动进行这些更改会很痛苦。只需稍加修改,您就可以让 Swift 为您工作。

    尝试更改函数头:

    func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
                                    readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
                 {
    

    到一个闭包声明:

    let MyMIDIReadProc: MIDIReadProc = {pktList, readProcRefCon, srcConnRefCon in
    

    Swift 以这种风格完美地推断参数类型。

    您可能需要修复指针类型转换:

        let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(OpaquePointer(srcConnRefCon)).pointee;
    

    到这样的事情:

        //I'm not sure using `!` is safe here...
        let srcRef: MIDIEndpointRef = UnsafeMutablePointer(srcConnRefCon!).pointee
    

    (顺便说一句,你的 Xcode 7 代码中的等效部分有点多余。你不需要在那里使用中间的COpaquePointer。)


    在 Swift 3 中,指针不能为 nil,可空指针用 Optionals 表示。您可能需要进行许多其他修复才能在 Swift 3 中使用基于 C 的 API。

    【讨论】:

      【解决方案2】:

      OOPer 正在为您指明(咳咳)正确的方向。这是一篇关于使用 Swift 3 Core MIDI 以及工作 github 存储库的博文。

      【讨论】:

        【解决方案3】:

        假设您使用的是 CoreMIDI 1.3 或更高版本,使用MIDIInputPortCreateWithBlock 而不是MIDIInputPortCreate 可能会更幸运。

        此方法将 Swift 块作为参数,而不需要 @convention(c) 函数引用,使其更适合在属于 Swift 类的方法中使用,例如:

        public func midiReadBlock(ptr: UnsafePointer<MIDIPacketList>, _: UnsafeMutableRawPointer?) -> Void {
            let list: MIDIPacketList = ptr.pointee
            ...
        }
        

        您可能还会发现这两个扩展很有用。

        这个(源自here)允许您使用for pkt in list 直接迭代MIDIPacketList

        extension MIDIPacketList: Sequence {
        
            public func makeIterator() -> AnyIterator<MIDIPacket> {
                var iterator: MIDIPacket?
                var nextIndex: UInt32 = 0
        
                return AnyIterator {
                    nextIndex += 1
                    if nextIndex > self.numPackets { return nil }
                    if iterator != nil {
                        iterator = withUnsafePointer(to: &iterator!) { MIDIPacketNext($0).pointee }
                    } else {
                        iterator = self.packet;
                    }
                    return iterator
                }
            }
        }
        

        这个添加了一个方法到 MIDIPacket 以将内容提取为 [UInt8] 而不必使用真正损坏的元组语法:

        extension MIDIPacket {
            public var asArray: [UInt8] {
                let mirror = Mirror(reflecting: self.data)
                let length = Int(self.length)
        
                var result = [UInt8]()
                result.reserveCapacity(length)
        
                for (n, child) in mirror.children.enumerated() {
                    if n == length {
                        break
                    }
                    result.append(child.value as! UInt8)
                }
                return result
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2017-02-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-11-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多