我是 swift 的新手,我在处理非托管 CFString(或 NSString)的指针时遇到了一些困难。 我正在开发一个 CoreMIDI 项目,该项目暗示使用了 UnsafeMutablePointer?> 如您在此函数中所见:
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)
我没有在互联网上的苹果开发者库中找到任何使用 CoreMIDI 函数的示例代码。 我真的很困惑,因为我来自 cpp 并且在 swift 中有很多不同。
编辑:
在 Rintaro 和 Martin 回答后我仍然有问题,我所有的测试都是在 iOS 8.1 上完成的,如果我复制你给我的代码编译器告诉我我不能写:
let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property)
“Unmanaged”中的结果不可转换为“MIDIObjectRef”。
所以我添加了一个“&”,因为 MIDIObjectRef 是一个 UnsafeMutablePointer
let midiEndPoint = MIDIGetSource(0)
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property)
现在:“Unmanaged
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 正在等待的参数。
源“0”确实存在于我的 iPad 上,因为 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找到了解决办法,貌似MIDIObjectRef在32位和64位架构下有两种不同的定义。当我在旧 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 位设备...
感谢您宝贵的帮助
最佳答案
我没有使用 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 :
NOTE
When passing a Core Foundation object to a MIDI function, the MIDI function will never consume a reference to the object. The caller always retains a reference which it is responsible for releasing by calling the CFRelease function.
When receiving a Core Foundation object as a return value from a MIDI function, the caller always receives a new reference to the object, and is responsible for releasing it.
参见 "Working with Cocoa Data Types" 中的“非托管对象”获取更多信息。
更新:以上代码仅在 64 位模式下编译时有效。在 32 位模式下,
MIDIObjectRef
和 MIDIEndpointRef
被定义为不同类型的指针。
这在 (Objective-)C 中没有问题,但 Swift 不允许直接转换,一个
这里需要“不安全的转换”:
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)")
}
}
关于ios - Swift UnsafeMutablePointer<Unmanaged<CFString>?> 分配和打印,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27169807/