Swift中的“向下倾斜”C结构

时间:2014-12-29 13:48:32

标签: ios swift

Core MIDI是一种C API,提供其他地方找不到的功能。

当用户的MIDI设置发生变化时(例如您插入设备),会有通知。

这是被调用的函数的类型。

typealias MIDINotifyProc = CFunctionPointer<((UnsafePointer<MIDINotification>, UnsafeMutablePointer<Void>) -> Void)>

第一个参数是MIDINotification结构,如下所示:

struct MIDINotification {
    var messageID: MIDINotificationMessageID
    var messageSize: UInt32
}

您可以像这样实现回调:

func MyMIDINotifyProc (np:UnsafePointer<MIDINotification>, refCon:UnsafeMutablePointer<Void>) {        
    var notification = np.memory       
    switch (notification.messageID) {

    case MIDINotificationMessageID(kMIDIMsgObjectAdded):
        // In Objective-C you would just do a cast here
        // This is the problem line
        var m = np.memory as MIDIObjectAddRemoveNotification

您可以查看messageID成员,了解您刚刚收到的通知类型。有几个(我只展示一个)。对于每种通知,您将获得传入的不同结构。这是添加或删除设备时获得的结构:

struct MIDIObjectAddRemoveNotification { 
    var messageID: MIDINotificationMessageID
    var messageSize: UInt32
    var parent: MIDIObjectRef
    var parentType: MIDIObjectType
    var child: MIDIObjectRef
    var childType: MIDIObjectType
}

如您所见,此结构具有其他信息。例如,“child”可能是设备的端点,因此您需要这些字段。

问题是从MIDINotification结构(回调签名所需)转换为MIDIObjectAddRemoveNotification。我使用“as”显示的行不起作用。

对于这种“向下倾斜”,您有什么建议吗?

3 个答案:

答案 0 :(得分:2)

我建议您查看标准库函数unsafeBitCast

答案 1 :(得分:2)

由于Vatsal Manot suggested,由于MIDINotificationMIDIObjectAddRemoveNotification与任何继承或契约无关,因此Swift无法在这些结构之间执行任何安全投射。

您需要使用unsafeBitCast函数明确地强制转换它:

case MIDINotificationMessageID(kMIDIMsgObjectAdded):
    let m = unsafeBitCast(np.memory, MIDIObjectAddRemoveNotification.self)

请注意,此函数始终可以在Swift中用于执行强制转换,但它非常不安全,您应该仅将其用作最后一种可能的解决方案。

答案 2 :(得分:1)

你忘了一件事。即使是Obj-C,施法总是在指针上发生。你不能把记忆转移到记忆中(好吧,有时你可以,重新解释它,但它不是很安全)。

let notification = np.memory

switch (notification.messageID) {            
    case MIDINotificationMessageID(kMIDIMsgObjectAdded):
       //cast the pointer!
       let addedNp = UnsafeMutablePointer<MIDIObjectAddRemoveNotification>(np)
       //now you can just access memory directly
       var m = addedNp.memory
}