我是swift的新手,我在处理非托管CFString(或NSString)的指针时遇到了一些困难。 我正在开发一个暗示使用UnsafeMutablePointer的CoreMIDI项目?>正如你在这个函数中看到的那样:
func MIDIObjectGetStringProperty(_ obj: MIDIObjectRef,
_ propertyID: CFString!,
_ str: UnsafeMutablePointer<Unmanaged<CFString>?>) -> OSStatus
我的问题是我想分配一个缓冲区来接收属性的内容(_str),然后调用上面的函数,最后使用println在控制台中打印内容。
目前我写了这个:
// Get the first midi source (I know it exists)
var midiEndPoint : Unmanaged<MIDIEndpointRef> = MIDIGetSource(0)
//C reate a "constant" of 256
let buf = NSMutableData(capacity: 256)
// Allocate a string buffer of 256 characters (I'm not even sure this does what I want)
var name = UnsafeMutablePointer<Unmanaged<CFString>?>(buf!.bytes)
// Call the function to fill the string buffer with the display name of the midi device
var err : OSStatus = MIDIObjectGetStringProperty(&midiEndPoint,kMIDIPropertyDisplayName,name)
// Print the string ... here no surprises I don't know what to write to print the content of the pointer, so it prints the address for the moment
println(name)
我没有找到任何示例代码来在Apple开发者库上使用CoreMIDI函数而不是在互联网上。 我真的很困惑,因为我来自cpp,而且很快就会有很多不同。
编辑:
在Rintaro和Martin回答之后我仍然有问题,我的所有测试都在iOS 8.1上完成,如果我复制你带给我的代码,编译器会告诉我我不能写:
let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property)
'Unmanaged'中的结果不能转换为'MIDIObjectRef'。 所以我加了一个“&amp;”因为MIDIObjectRef是一个UnsafeMutablePointer&lt; void&gt;。
let midiEndPoint = MIDIGetSource(0)
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property)
现在:'未管理&lt; MIDIEndpoint&gt;'不能转换为'@lvalue inout $ T2'。最后我不得不改变第一个let到var,而不理解为什么?!?
var midiEndPoint = MIDIGetSource(0)
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property)
代码现在编译并运行,但MIDIObjectGetStringProperty返回OSStatus err -50,它对应于IOW或MacErros.h:
paramErr = -50, /*error in user parameter list*/
所以参数似乎不是MIDIObjectGetStringProperty正在等待的参数。
我的iPad上确实存在源“0”,因为MIDIGetNumberOfSources()返回1.这是完整的代码:
var numDestinations: ItemCount = MIDIGetNumberOfDestinations()
println("MIDI Destinations : " + String(numDestinations))
for var i : ItemCount = 0 ; i < numDestinations; ++i{
var midiEndPoint = MIDIGetDestination(i)
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property)
if err == noErr {
let displayName = property!.takeRetainedValue() as String
println(displayName)
}else{
println("error : "+String(err))
}
}
显示:
MIDI Destinations : 1
error : -50
我真的什么都不懂......
更新:
最后,Martin找到了解决方案,似乎在32位和64位架构中有两种不同的MIDIObjectRef定义。当我在旧iPad 2上运行代码时,我的代码尝试在32位模式下编译,其中MIDIGetSource(i)返回值不可转换为MIDIObjectRef。解决方案是在32位架构上“不安全地转换”midi端点:
#if arch(arm64) || arch(x86_64)
let midiEndPoint = MIDIGetDestination(i)
#else
let midiEndPoint = unsafeBitCast(MIDIGetDestination(i), MIDIObjectRef.self)
#endif
...或购买新的64位设备......
感谢您的宝贵帮助
答案 0 :(得分:8)
我没有使用CoreMIDI的经验而且无法测试它,但这是它应该如何工作:
let midiEndPoint = MIDIGetSource(0)
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property)
if err == noErr {
let displayName = property!.takeRetainedValue() as String
println(displayName)
}
正如@rintaro正确注意到的那样,takeRetainedValue()
是正确的选择,因为释放字符串是调用者的责任。这不同于
通常的Core Foundation内存管理规则,但记录在
MIDI Services Reference:
请注意
将Core Foundation对象传递给MIDI函数时,MIDI 函数永远不会消耗对象的引用。呼叫者,召集者 总是保留一个它负责释放的参考 调用CFRelease函数。
从MIDI接收Core Foundation对象作为返回值时 函数,调用者总是收到对象的新引用, 并负责释放它。
有关详细信息,请参阅"Working with Cocoa Data Types"中的“非托管对象”。
更新:以上代码仅在以64位模式编译时有效。在32位模式下,
MIDIObjectRef
和MIDIEndpointRef
被定义为不同类型的指针。
这在(Objective-)C中没有问题,但是Swift不允许直接转换,a
“不安全演员”在这里是必要的:
let numSrcs = MIDIGetNumberOfSources()
println("number of MIDI sources: \(numSrcs)")
for srcIndex in 0 ..< numSrcs {
#if arch(arm64) || arch(x86_64)
let midiEndPoint = MIDIGetSource(srcIndex)
#else
let midiEndPoint = unsafeBitCast(MIDIGetSource(srcIndex), MIDIObjectRef.self)
#endif
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property)
if err == noErr {
let displayName = property!.takeRetainedValue() as String
println("\(srcIndex): \(displayName)")
} else {
println("\(srcIndex): error \(err)")
}
}