我正在使用Swift与Core进行交互,MIDIThruConnectionFind函数也有一些问题。
文档声明如下
func MIDIThruConnectionFind(_ inPersistentOwnerID: CFString,
_ outConnectionList: UnsafeMutablePointer<Unmanaged<CFData>>) -> OSStatus这是我的功能,无论我尝试什么,我都会得到构建错误。例如,变量被使用,但没有初始化,类型错误等等。
@IBAction func listConnections(_ sender: Any) {
var connectionRef: Unmanaged<CFData>
MIDIThruConnectionFind("" as CFString, &connectionRef)
}我所期望的是,我应该为outConnectionList提供一个指针的入口,并且该函数为数据分配内存。但我该怎么用斯威夫特呢?
更新
至少这是编译的,但是如何去引用和访问数据呢?
@IBAction func listConnections(_ sender: Any) {
let connectionRefs = UnsafeMutablePointer<Unmanaged<CFData>>.allocate(capacity: 1)
MIDIThruConnectionFind("" as CFString, connectionRefs)
}发布于 2019-04-27 11:00:18
我有点猜测,目前还不能实际测试代码,但以下是我的想法:
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头中该函数的空注释中的一个bug。其他带有out参数的核心MIDI函数被正确地注释。
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)发布于 2020-12-29 11:48:24
// Creates an unmanaged<CFData>>
var unmanagedData = Unmanaged.passUnretained(Data() as CFData)是否使用保留或未保留取决于上下文。对于coreMidi对象,我假设CoreMidi负责内存管理。
下面是两个与CoreMidi交互的函数的例子。一个用于单个值,另一个用于值数组(如在您的问题中)。
注意,在现实生活中,最好将函数声明为抛出,并在CoreMidi函数返回错误时抛出一些快速错误。在这个例子中,如果失败,我们只返回0。
单值情况
func getMidiThruParams(connectionRef: MIDIThruConnectionRef) -> MIDIThruConnectionParams? {
// 1 - allocate an unmanaged CFData
var unmanagedData = Unmanaged.passUnretained(Data() as CFData)
// 2 - Pass the data pointer to C API
let err = MIDIThruConnectionGetParams(connectionRef, &unmanagedData)
guard err == noErr else {
return nil
}
// 3 - Extract the data from unmanaged CFData
let data = unmanagedData.takeUnretainedValue() as Data
// 4 - Remap to the swift type
return data.withUnsafeBytes { bytes -> MIDIThruConnectionParams in
UnsafeRawPointer(bytes).assumingMemoryBound(to: MIDIThruConnectionParams.self).pointee
}
}阵列案例
func getMidiThruConnections() -> [MIDIThruConnectionRef]? {
// 1 - allocate an unmanaged data reference
var unmanagedData = Unmanaged.passUnretained(Data() as CFData)
// 2 - Pass the data pointer to C API
let err = MIDIThruConnectionFind("com.moosefactory.midiCenter.midiThru" as CFString, &unmanagedData)
guard err == noErr else {
return nil
}
// 3 - Extract the CFData from unmanaged data
// We prefer CFData to Data here, to access pointer and size
let cfData = unmanagedData.takeUnretainedValue()
guard let dataPtr = CFDataGetBytePtr(cfData) else {
return nil
}
// 4 - Compute the number of elements
let dataSize = CFDataGetLength(cfData)
let numberOfConnections = dataSize / MemoryLayout<MIDIThruConnectionRef>.stride
// 5 - Rebound pointer from <Int8> to <MIDIThruConnectionRef>
return dataPtr.withMemoryRebound(to: MIDIThruConnectionRef.self,
capacity: numberOfConnections) { typedPtr in
// Convert pointer to buffer pointer
let bufferPointer = UnsafeBufferPointer(start: typedPtr, count: numberOfConnections)
// Construct array
return [MIDIThruConnectionRef].init(unsafeUninitializedCapacity: numberOfConnections) { refPtr, count in
count = numberOfConnections
for i in 0..<count {
refPtr[i] = bufferPointer[i]
}
}
}
}https://stackoverflow.com/questions/55879035
复制相似问题