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

Core MIDI是一种C API,提供其他地方没有的function。

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

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

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

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

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

您可以像这样实现回调:

 func MyMIDINotifyProc (np:UnsafePointer, refCon:UnsafeMutablePointer) { 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”显示的行不起作用。

你对这种“向下转型”有什么建议吗?

正如Vatsal Manot所说 ,由于MIDINotificationMIDIObjectAddRemoveNotification与任何inheritance或契约无关,因此Swift无法在这些结构之间执行任何安全转换。

你需要使用unsafeBitCast函数显式地unsafeBitCast它:

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

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

我建议你研究标准库函数unsafeBitCast

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

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