I'm new to swift and I have some difficulties to deal with pointers of unmanaged CFString (or NSString). I'm working on a CoreMIDI project that implies usage of UnsafeMutablePointer?> as you can see in this function :
func MIDIObjectGetStringProperty(_ obj: MIDIObjectRef,
_ propertyID: CFString!,
_ str: UnsafeMutablePointer<Unmanaged<CFString>?>) -> OSStatus
My problem is that I want to allocate a buffer to receive the content of the property (_str) then call the function above, and finally print the content in the console by using println.
At the moment I wrote this :
// 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)
I didn't find any sample code to use CoreMIDI functions on apple developper library not on the internet. I really confused because I come from cpp and things are a lot different in swift.
EDIT :
After Rintaro and Martin answers I still have a problem, all my test are done on iOS 8.1 and if I copy the code you brought to me the compiler tells me that I can't write :
let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property)
Results in 'Unmanaged' is not convertible to 'MIDIObjectRef'. So I added a "&" because MIDIObjectRef is a UnsafeMutablePointer<void>.
let midiEndPoint = MIDIGetSource(0)
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property)
Now : 'Unmanaged<MIDIEndpoint>' is not convertible to '@lvalue inout $T2'. Finally I had to change the first let to var, without understanding why ?!?
var midiEndPoint = MIDIGetSource(0)
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property)
The code now compiles and runs but MIDIObjectGetStringProperty returns OSStatus err -50 which corresponds to IOW or from MacErros.h :
paramErr = -50, /*error in user parameter list*/
So it seems that the parameters are not the ones that MIDIObjectGetStringProperty is waiting for.
The source "0" does exist on my iPad because MIDIGetNumberOfSources() returns 1. Here's the complete code :
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))
}
}
Displays :
MIDI Destinations : 1
error : -50
I really don't understand anything ...
UPDATE :
Finally Martin found the solution, it seems that there are two different definitions of MIDIObjectRef in 32 and 64bits architectures. As I run the code on an old iPad 2 my code tried to compile in 32bits mode where MIDIGetSource(i) return value is not convertible into MIDIObjectRef. The solution is to "unsafe cast" the midi endpoint on 32 bits architectures :
#if arch(arm64) || arch(x86_64)
let midiEndPoint = MIDIGetDestination(i)
#else
let midiEndPoint = unsafeBitCast(MIDIGetDestination(i), MIDIObjectRef.self)
#endif
... Or to buy a new 64bit device ...
Thank you for the precious help
takeRetainedValue()
, because in this case, we have responsibility to release returnedCFString
. – Prudery