2014-12-29 2 views
8

Core MIDI - это API C, который предоставляет возможности, не найденные в других местах.«Downcasting» C Structs in Swift

Когда пользовательская настройка 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. Строка, которую я показал с помощью «как», не работает.

Есть ли у вас какие-либо предложения по поводу такого «понижения»?

ответ

2

Предлагаю вам ознакомиться со стандартной библиотечной функцией unsafeBitCast.

2

Как Vatsal Manot suggested, так как MIDINotification и MIDIObjectAddRemoveNotification не связаны никаким наследством или договором, Swift не может осуществлять безопасное литье между этими структурами.

Вам нужно бросить его в явном виде с помощью unsafeBitCast функции:

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

Обратите внимание, что эта функция всегда может быть использована в Swift для выполнения слепков, но это крайне небезопасно, и вы должны использовать его только как последнее возможное решение.

+0

Обновление: Ну, это сработало некоторое время. Теперь он разбит на Swift 2.0 beta. –

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 
}