Swift UnsafeMutablePointer> распределение и печать

Я новичок в 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 в библиотеке Apple developper не в интернете. Я действительно смущен, потому что я пришел из cpp, и в swift все по-другому.

EDIT:

после ответов Rintaro и Martin у меня все еще есть проблема, все мои тесты выполняются на iOS 8.1, и если я скопирую код, который вы мне принесли, компилятор скажет мне, что я не могу написать :

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

результаты в "неуправляемом" не кабриолет на "MIDIObjectRef". Поэтому я добавил"&", Потому что MIDIObjectRef является UnsafeMutablePointer.

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

теперь: 'Unmanaged' не конвертируется в '@lvalue inout $T2'. Наконец, я должен был изменить первый let на var, не понимая, почему ?!?

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

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

обновление :

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

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

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

Спасибо за помощь

1 ответов


у меня нет опыта работы с 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 услуги ссылка:

Примечание

при прохождении основного фундамента объект для функции MIDI, MIDI функция никогда не будет использовать ссылку на объект. Абонент всегда сохраняет ссылку, которую он несет ответственность за освобождение вызова CFRelease.

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

см. раздел "неуправляемые объекты" в "работа с данными какао Типы" для получения дополнительной информации.

обновление: приведенный выше код работает только при компиляции в 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)")
    }
}