2014-11-27 7 views
6

Ich bin neu zu schnell und ich habe einige Schwierigkeiten, mit Zeigern von nicht verwalteten CFString (oder NSString) umzugehen. Ich arbeite an einem Projekt, die Coremidi Nutzung von UnsafeMutablePointer impliziert>, wie Sie in dieser Funktion sehen:Swift UnsafeMutablePointer <Unmanaged ?> Zuordnung und Drucken

func MIDIObjectGetStringProperty(_ obj: MIDIObjectRef, 
          _ propertyID: CFString!, 
          _ str: UnsafeMutablePointer<Unmanaged<CFString>?>) -> OSStatus 

Mein Problem ist, dass ich einen Puffer zu erhalten, den Inhalt der Eigenschaft zugewiesen werden soll (_str) Rufen Sie dann die obige Funktion auf und drucken Sie den Inhalt schließlich mit println in der Konsole aus.

Im Moment habe ich dies:

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

ich nicht im Internet keinen Beispielcode finden, um Coremidi-Funktionen auf Apfel developper Bibliothek zu verwenden. Ich bin wirklich verwirrt, weil ich von cpp komme und die Dinge sind sehr unterschiedlich in swift.

EDIT:

Nach Rintaro und Martin Antworten, die ich habe immer noch ein Problem, alle meine Tests sind auf iOS getan 8.1 und wenn ich kopieren Sie den Code, den Sie zu mir gebracht der Compiler sagt mir, dass ich nicht schreiben kann:

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

Ergebnisse in "Unmanaged" ist nicht in "MIDIObjectRef" konvertierbar. Also habe ich eine "&" hinzugefügt, weil MIDIObjectRef ist ein unsafeMutablePointer <void>.

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

Jetzt: 'Unmanaged <MIDIEndpoint>' ist nicht konvertierbar '@lvalue inout $ T2'. Schließlich musste ich das erste mal auf var umstellen, ohne zu verstehen warum?!?

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

Der Code kompiliert jetzt und läuft, aber MIDIObjectGetStringProperty gibt OSStatus -50 irren, die IOW oder von MacErros.h entspricht:

paramErr = -50, /*error in user parameter list*/ 

So scheint es, dass die Parameter sind nicht diejenigen, die MIDIObjectGetStringProperty ist warten auf.

Die Quelle "0" nicht auf meinem iPad existieren, weil MIDIGetNumberOfSources() gibt 1. Hier ist der vollständige 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 

ich etwas verstehe wirklich nicht. ..

UPDATE:

Schließlich fand Martin die Lösung, Es scheint, dass es zwei unterschiedliche Definitionen von MIDIObjectRef in 32- und 64-Bit-Architekturen gibt. Als ich den Code auf einem alten iPad 2 ausführte, versuchte mein Code, im 32bits Modus zu kompilieren, in dem MIDIGetSource (i) Rückgabewert nicht in MIDIObjectRef umwandelbar ist. Die Lösung ist „unsicher cast“ der MIDI-Endpunkt auf 32-Bit-Architekturen:

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

... Oder ein neues 64-Bit-Geräte zu kaufen ...

Vielen Dank für die wertvolle Hilfe

Antwort

7

ich keine Erfahrung mit Coremidi haben und es nicht testen konnte, aber das ist, wie es funktionieren sollte:

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

Als @rintaro richtig bemerkte takeRetainedValue() ist die richtige Wahl hier, weil es die Anrufer Verantwortung ist, die Zeichenfolge freizugeben. Dies unterscheidet sich von den üblichen Core Foundation Speicher-Management-Regeln, aber in der MIDI Services Reference dokumentiert:

HINWEIS

Beim Passieren eines Core Foundation Objekt in eine MIDI-Funktion, die MIDI Funktion niemals verbrauchen eine

Referenz auf das Objekt. Der Aufrufer behält immer eine Referenz, für deren Freigabe er verantwortlich ist, indem er die CFRelease-Funktion aufruft, indem er aufruft.

Wenn ein Core Foundation-Objekt als Rückgabewert von einer MIDI-Funktion empfangen wird, erhält der Aufrufer immer einen neuen Verweis auf das Objekt und ist für die Freigabe verantwortlich.

Weitere Informationen finden Sie unter "Nicht verwaltete Objekte" unter "Working with Cocoa Data Types".

UPDATE: Der obige Code funktioniert nur beim Kompilieren im 64-Bit-Modus. Im 32-Bit-Modus sind MIDIObjectRef und MIDIEndpointRef als unterschiedliche Arten von Zeigern definiert. Das ist kein Problem in (objektiv-) C, aber Swift eine direkte Umwandlung nicht erlaubt, ein „unsicher cast“ ist notwendig, hier:

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)") 
    } 
} 
+0

Ich bestätigte dies funktioniert, aber ich denke, wir 'takeRetainedValue verwenden sollten() ', denn in diesem Fall haben wir die Verantwortung, den zurückgegebenen' CFString' freizugeben. – rintaro

+0

@rintaro: "MIDIObjectGetStringProperty" hat in seinem Namen nicht "Create" oder "Copy". Gemäß den Speicherverwaltungsregeln von Core Foundation ist der Aufrufer nicht für die Freigabe des Speichers verantwortlich. Siehe https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html. Ich denke, dass die "Get Rule" hier gilt. –

+0

Aber tatsächlich habe ich bestätigt, dass es Lecks gibt. siehe: https://developer.apple.com/library/mac/qa/qa1374/_index.html – rintaro

Verwandte Themen