Я немного догадываюсь и не могу на самом деле проверить код в данный момент, но вот мои мысли:
Функция MIDIThruConnectionFind()
объявлена в MIDIThruConnection.h как
extern OSStatus
MIDIThruConnectionFind( CFStringRef inPersistentOwnerID,
CFDataRef __nonnull * __nonnull outConnectionList )
и поэтому импортируется в Swift как
public func MIDIThruConnectionFind(_ inPersistentOwnerID: CFString,
_ outConnectionList: UnsafeMutablePointer<Unmanaged<CFData>>) -> OSStatus
, что означает, что последний параметр должен быть адресом (инициализированного и) необязательного Unmanaged<CFData>
значения.
Но это не имеет смысла: данные распределяются функцией, и мы не хотим передавать какие-либо данные. Я настоятельно предполагаю, что это ошибка в аннотации обнуляемости этой функции в заголовке C. Другие основные MIDI-функции с параметром out правильно аннотированы, например,
extern OSStatus
MIDIObjectGetStringProperty( MIDIObjectRef obj,
CFStringRef propertyID,
CFStringRef __nullable * __nonnull str )
Может работать следующий обходной путь: Объявите connectionRef
как необязательный указатель (так, чтобы он был инициализирован как nil
), и «приведите» его к необязательному указателю при вызове функции :
var connectionRef: Unmanaged<CFData>?
let status = withUnsafeMutablePointer(to: &connectionRef) {
$0.withMemoryRebound(to: Unmanaged<CFData>.self, capacity: 1) {
MIDIThruConnectionFind("" as CFString, $0)
}
}
Если это удастся, необязательный указатель может быть развернут, и ссылка CFData
получена с помощью takeRetainedValue()
. CFData
предоставляется по бесплатному мосту NSData
, и его можно привести к типу оверлея Swift Data
:
if status == noErr, let connectionRef = connectionRef {
let data = connectionRef.takeRetainedValue() as Data
}
Другим обходным решением является определение функции-оболочки с правильными аннотациями обнуляемости в файле заголовка моста:
#include <CoreMIDI/CoreMIDI.h>
static OSStatus myMIDIThruConnectionFind(CFStringRef inPersistentOwnerID,
CFDataRef __nullable * __nonnull outConnectionList) {
return MIDIThruConnectionFind(inPersistentOwnerID, outConnectionList);
}
, который затем можно назвать
var connectionRef: Unmanaged<CFData>?
let status = myMIDIThruConnectionFind("" as CFString, &connectionRef)