在 Swift 中“向下转换”C 结构
Posted
技术标签:
【中文标题】在 Swift 中“向下转换”C 结构【英文标题】:"Downcasting" C Structs in Swift 【发布时间】:2014-12-29 13:48:32 【问题描述】: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
如你所见,这个结构有额外的信息。例如,“孩子”可能是设备的端点,因此您需要这些字段。
问题是从 MIDINotification 结构(回调签名要求)转换为 MIDIObjectAddRemoveNotification。我使用“as”显示的行不起作用。
你对这种“低调”有什么建议吗?
【问题讨论】:
【参考方案1】:作为Vatsal Manot suggested,由于MIDINotification
和MIDIObjectAddRemoveNotification
没有任何继承或契约相关,Swift 无法在这些结构之间执行任何安全转换。
您需要使用unsafeBitCast
函数显式转换它:
case MIDINotificationMessageID(kMIDIMsgObjectAdded):
let m = unsafeBitCast(np.memory, MIDIObjectAddRemoveNotification.self)
请注意,此函数始终可以在 Swift 中用于执行强制转换,但它非常不安全,您应该仅将其用作最后可能的解决方案。
【讨论】:
更新:它工作了一段时间。它现在在 Swift 2.0 beta 中被破坏了。【参考方案2】:我建议你查看标准库函数unsafeBitCast
。
【讨论】:
【参考方案3】:你忘记了一件事。即使是 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
【讨论】:
以上是关于在 Swift 中“向下转换”C 结构的主要内容,如果未能解决你的问题,请参考以下文章
Swift 模式匹配 - 在单个语句中切换、向下转换和可选绑定
使用 Google Drive REST API 在 Swift 3 完成处理程序中避免向下转换
使用 XCode 7 和 Swift 向下转换的核心数据 NSManagedObject
什么是 Swift 中的桥接转换,如以下警告所示:来自“数据?”的条件向下转换to 'CKRecordValue 是一种桥接转换