2014-11-27 4 views
6

Я новичок в быстром, и у меня есть некоторые трудности с указателями неуправляемого CFString (или NSString). Я работаю над проектом CoreMIDI, который подразумевает использование UnsafeMutablePointer> как вы можете видеть в этой функции:?Swift 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 на яблоне developper библиотеки не в Интернете. Я действительно смущен, потому что я родом из cpp, и все очень быстро меняется.

EDIT:

После Ринтары и Мартина ответы, которые я до сих пор есть проблемы, все мои испытания выполняются на прошивке 8.1 и если я скопировать код, который вы принесли мне компилятор говорит мне, что я не могу написать:

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

Результаты в «Неуправляемом» не конвертируются в «MIDIObjectRef». Итак, я добавил «&», потому что MIDIObjectRef является UnsafeMutablePointer <void>.

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

Теперь: 'Неуправляемый <MIDIEndpoint>' не конвертируются в '@lvalue Inout $ T2. Наконец, мне пришлось сменить первый вариант на var, не понимая почему?!?

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

Теперь код компилируется и работает, но MIDIObjectGetStringProperty возвращает OSStatus заблуждаться -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 

я действительно ничего не понимаю. ..

UPDATE:

Наконец Мартин нашел решение, кажется, что существует два разных определения MIDIObjectRef в 32 и 64-битных архитектурах. Когда я запускаю код на старом iPad 2, мой код пытался скомпилировать в режиме 32 бит, где возвращаемое значение MIDIGetSource (i) не конвертируется в MIDIObjectRef. Решение состоит в том, чтобы «небезопасный слепок» миди конечной точки на 32 бит архитектуры:

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

... Или купить новое устройство 64-битного ...

Спасибо за ценную помощь

ответ

7

у меня нет опыта работы с 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() является правильный выбор здесь, потому что это звонящие ответственность за выпуск строки. Это отличается от обычных правил управления памятью ядро ​​Foundation, но документированы в MIDI Services Reference:

ПРИМЕЧАНИЕ

При передаче объекта ядра Foundation к функции MIDI, функция MIDI никогда не будет потреблять ссылка на объект. Вызывающий абонент всегда сохраняет ссылку, на которую отвечает освобождение на , вызывающее функцию CFRelease.

При получении объекта Core Foundation в качестве возвращаемого значения из функции MIDI вызывающий объект всегда получает новую ссылку на объект, и несет ответственность за его освобождение.

Для получения дополнительной информации см. «Неуправляемые объекты» в "Working with Cocoa Data Types".

ОБНОВЛЕНИЕ: Приведенный выше код работает только при компиляции в 64-разрядном режиме. В 32-битном режиме MIDIObjectRef и MIDIEndpointRef определяются как различные указатели. Это не проблема (объективно-) 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)") 
    } 
} 
+0

Я подтвердил, что это работает, но я думаю, что мы должны использовать 'takeRetainedValue() ', потому что в этом случае мы несем ответственность за выпуск возвращенного' CFString'. – rintaro

+0

@ rintaro: «MIDIObjectGetStringProperty» не имеет «Создать» или «Копировать» в его имени. Согласно правилам управления памятью Core Foundation, это означает, что вызывающий абонент не несет ответственности за освобождение памяти. См. Https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html. Я думаю, что здесь применяется «Get Rule». –

+0

Но, фактически, я подтвердил, что он протекает. см. https://developer.apple.com/library/mac/qa/qa1374/_index.html – rintaro