Swift UnsafeMutablePointer <Unmanaged <CFString>?>分配和打印

我是新来的迅速,我有一些困难来处理非托pipeCFString(或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) 

我没有find任何示例代码来使用苹果开发者库上的CoreMIDIfunction,而不是在互联网上。 我真的很困惑,因为我来自cpp,而且事情有很大的不同。

编辑:

Rintaro和Martin的回答之后,我仍然有一个问题,我所有的testing都是在iOS 8.1上完成的,如果我复制了带给我的代码,编译器告诉我我不能写:

 let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property) 

“Unmanaged”中的结果不能转换为“MIDIObjectRef”。 所以我添加了一个“&”,因为MIDIObjectRef是一个UnsafeMutablePointer <void>。

 let midiEndPoint = MIDIGetSource(0) var property : Unmanaged<CFString>? let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property) 

现在:'非托pipe<MIDIEndpoint>'不能转换为'@lvalue inout $ T2'。 最后我不得不改变第一个让var,不明白为什么?!?

 var midiEndPoint = MIDIGetSource(0) var property : Unmanaged<CFString>? let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property) 

代码现在编译并运行,但MIDIObjectGetStringProperty返回对应于IOW或来自MacErros.h的OSStatus err -50:

 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 

我真的不明白

更新:

最后,Martinfind了解决scheme,似乎在32位和64位体系结构中有两种不同的MIDIObjectRef定义。 当我在旧的iPad 2上运行代码时,我的代码试图在32位模式下编译MIDIGetSource(i)返回值不能转换为MIDIObjectRef。 解决scheme是在32位体系结构上“不安全地”投射midi端点:

 #if arch(arm64) || arch(x86_64) let midiEndPoint = MIDIGetDestination(i) #else let midiEndPoint = unsafeBitCast(MIDIGetDestination(i), MIDIObjectRef.self) #endif 

…或者购买一个新的64位设备…

感谢您的宝贵帮助

我没有CoreMIDI的经验,无法testing它,但这是它应该如何工作:

 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) } 

正如@印记正确地注意到, takeRetainedValue()在这里是正确的select,因为它是呼叫者负责释放string。 这与通常的Core Foundation内存pipe理规则不同,但在MIDI服务参考中有logging :

注意

将Core Foundation对象传递给MIDI函数时,MIDI函数永远不会消耗对该对象的引用。 调用者通过调用CFRelease函数总是保留一个引用,它负责释放。

当从MIDI函数接收到作为返回值的Core Foundation对象时,调用者总是接收到对象的新引用,并负责释放它。

有关更多信息,请参阅“ 使用cocoa数据types”中的 “非托pipe对象”。

更新:上述代码仅在64位模式下编译时才起作用。 在32位模式下, MIDIObjectRefMIDIEndpointRef被定义为不同types的指针。 (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)") } }