9

私はswiftが初めてで、管理されていないCFString(またはNSString)のポインターを処理するのにいくつかの困難があります。この関数でわかるように、UnsafeMutablePointer?> の使用を意味する CoreMIDI プロジェクトに取り組んでいます。

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 関数を使用するためのサンプル コードが見つかりませんでした。私はcppから来て、swiftでは状況が大きく異なるため、本当に混乱しました。

編集 :

Rintaro と Martin が私にまだ問題があると答えた後、私のテストはすべて iOS 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)

現在: 'Unmanaged<MIDIEndpoint>' は '@lvalue inout $T2' に変換できません。最後に、理由を理解せずに、最初の let を 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 が待機しているものではないようです。

MIDIGetNumberOfSources() が 1 を返すため、ソース "0" は私の iPad に存在します。完全なコードは次のとおりです。

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

私は本当に何も理解していません...

アップデート :

最後に、Martin は解決策を見つけました。32 ビットと 64 ビットのアーキテクチャには、MIDIObjectRef の 2 つの異なる定義があるようです。古い iPad 2 でコードを実行すると、私のコードは、MIDIGetSource(i) の戻り値が MIDIObjectRef に変換できない 32 ビット モードでコンパイルしようとしました。解決策は、32 ビット アーキテクチャで midi エンドポイントを「安全でないキャスト」することです。

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

... または、新しい 64 ビット デバイスを購入するには ...

貴重な助けをありがとう

4

1 に答える 1

12

私は 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 サービス リファレンスに記載されています。

ノート

Core Foundation オブジェクトを MIDI 関数に渡す場合、MIDI 関数はオブジェクトへの参照を消費しません。呼び出し元は、CFRelease 関数を呼び出して解放する責任がある参照を常に保持します。

Core Foundation オブジェクトを MIDI 関数からの戻り値として受け取る場合、呼び出し元は常にオブジェクトへの新しい参照を受け取り、それを解放する責任があります。

詳細については、 「Cocoa データ型の操作」の「管理されていないオブジェクト」を参照してください。

更新:上記のコードは、64 ビット モードでコンパイルする場合にのみ機能します。32 ビット モードで MIDIObjectRefMIDIEndpointRef、異なる種類のポインターとして定義されます。これは (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)")
    }
}
于 2014-11-27T13:07:17.613 に答える