Swift UnsafeMutablePointer< Unmanaged< CFString>?>分配和打印 [英] Swift UnsafeMutablePointer<Unmanaged<CFString>?> allocation and print

查看:170
本文介绍了Swift UnsafeMutablePointer< Unmanaged< CFString>?>分配和打印的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是swift的新手,处理非托管CFString(或NSString)的指针时遇到一些困难。
我正在开发一个暗示使用UnsafeMutablePointer?>的CoreMIDI项目,正如你在这个函数中看到的那样:

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

我的问题是我想分配一个缓冲区来接收属性的内容(_str)然后调用上面的函数,最后使用println在控制台中打印内容。

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.

目前我写了这个:

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

我没有找到任何示例代码来在Apple开发者库上使用CoreMIDI函数而不是在互联网上。
我真的很困惑,因为我来自cpp,而且swift中的情况有很多不同。

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.

编辑:

在Rintaro和Martin回答之后我仍然有问题,我的所有测试都在iOS 8.1上完成,如果我复制你带给我的代码,编译器会告诉我我不能写:

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)

'未管理'的结果不能转换为'MIDIObjectRef'。
所以我添加了一个&因为MIDIObjectRef是一个UnsafeMutablePointer< void> ;.

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)

现在: 'Unmanaged< MIDIEndpoint>'不能转换为'@lvalue inout $ T2'。最后我不得不改变第一个let到var,而不理解为什么?!

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)

代码现在编译并运行,但MIDIObjectGetStringProperty返回OSStatus err -50,它对应于IOW或MacErros.h:

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

所以参数似乎不是MIDIObjectGetStringProperty的参数正在等待。

So it seems that the parameters are not the ones that MIDIObjectGetStringProperty is waiting for.

我的iPad上存在源0,因为MIDIGetNumberOfSources()返回1.这是完整的代码:

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

显示:

MIDI Destinations : 1
error : -50

我真的什么都不懂......

I really don't understand anything ...

更新:

最后,Martin找到了解决方案,似乎在32位和64位架构中有两种不同的MIDIObjectRef定义。当我在旧iPad 2上运行代码时,我的代码试图在32位模式下编译,其中MIDIGetSource(i)返回值不能转换为MIDIObjectRef。解决方案是在32位架构上不安全地转换midi端点:

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

...或购买新的64位设备......

... Or to buy a new 64bit device ...

感谢您的宝贵帮助

推荐答案

我没有使用CoreMIDI的经验而且无法测试它,但这是怎么回事应该工作:

I have no experience with CoreMIDI and could not test it, but this is how it should work:

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内存管理规则不同,但在
中有记录麦迪服务参考

As @rintaro correctly noticed, takeRetainedValue() is the right choice here because it is the callers responsibility to release the string. This is different from the usual Core Foundation memory management rules, but documented in the MIDI Services Reference:


注意

NOTE

将Core Foundation对象传递给MIDI函数时,MIDI
函数将永远不会使用对象的引用。调用者
总是保留一个引用,它负责通过
调用CFRelease函数来释放。

When passing a Core Foundation object to a MIDI function, the MIDI function will never consume a reference to the object. The caller always retains a reference which it is responsible for releasing by calling the CFRelease function.

当收到Core Foundation对象作为返回时来自MIDI
函数的值,调用者总是收到对该对象的新引用,
并负责释放它。

When receiving a Core Foundation object as a return value from a MIDI function, the caller always receives a new reference to the object, and is responsible for releasing it.

请参阅使用Cocoa数据类型中的非托管对象 了解更多信息。

更新:以上代码仅在以64位模式编译时有效。在32位模式下,
MIDIObjectRef MIDIEndpointRef 被定义为不同类型的指针。
这在(Objective-)C中没有问题,但是Swift不允许直接转换,这里需要
不安全的演员:

UPDATE: The above code works only when compiling in 64-bit mode. In 32-bit mode, MIDIObjectRef and MIDIEndpointRef are defined as different kind of pointers. This is no problem in (Objective-)C, but Swift does not allow a direct conversion, an "unsafe cast" is necessary here:

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

这篇关于Swift UnsafeMutablePointer&lt; Unmanaged&lt; CFString&gt;?&gt;分配和打印的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆