当前位置: 首页 > 面试题库 >

Swift UnsafeMutablePointer?>分配并打印

饶明亮
2023-03-14
问题内容

我是新手,并且在处理非托管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函数,而不是在互联网上。我真的很困惑,因为我来自cpp,事情很快就大不相同了。

编辑:

在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正在等待的参数。

iPad上确实存在源“ 0”,因为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

我真的什么都不懂…

更新:

最终,马丁找到了解决方案,似乎在32位和64位体系结构中存在MIDIObjectRef的两种不同定义。当我在旧的iPad
2上运行代码时,我的代码试图以32位模式进行编译,其中MIDIGetSource(i)的返回值无法转换为MIDIObjectRef。解决方案是“不安全地”转换32位体系结构上的midi端点:

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

…或购买新的64位设备…

谢谢您的宝贵帮助


问题答案:

我没有使用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 Services
Reference中有记录:

注意

将Core
Foundation对象传递给MIDI函数时,MIDI函数将永远不会消耗对该对象的引用。调用方始终保留一个引用,它负责通过调用CFRelease函数来释放引用。

从MIDI函数接收Core Foundation对象作为返回值时,调用者始终会收到对该对象的新引用,并负责释放它。

有关更多信息,请参见“
使用可可数据类型”中的
“非托管对象” 。

更新: 上面的代码仅在以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)")
    }
}


 类似资料:
  • 本文向大家介绍grep 仅打印行的匹配部分,包括了grep 仅打印行的匹配部分的使用技巧和注意事项,需要的朋友参考一下 示例            

  • 如果我想重新分区一个数据帧,如何决定需要做的分区数量?如何决定是使用重新分区还是合并?我知道合并基本上只是为了减少分区的数量。但是我们如何决定在什么情况下使用哪个呢?

  • 我正在尝试拆分一个字符串并在某些print语句前面打印它的内容,但是我无法使用for循环来完成这件事。有人能帮忙吗? }

  • 我在低源硬件配置的机器上得到了1个节点、1个碎片、1个副本体系结构。我必须将Elasticsearch堆大小保持在总内存的20%,并且我索引1K~1M文档到Elasticsearch关于硬件配置。我有不同类型机器,从2GB到16GB,但由于它们是32bit体系结构,我只能使用300M到1.5GB的最大内存作为堆大小。 由于某些原因,我不知道为什么,Elasticsearch创建了一些带有未分配碎片

  • 问题内容: 我想要使用在Python中使用函数返回值将值分配给shell变量的解决方案的PHP等效方案 在我的php文件中,我读取了一些常量值,例如: 到目前为止,在我的shell脚本中,我有以下代码:- 我能够通过外壳正确执行文件。 要进一步了解我要执行的操作,请检查从PHP文件读取配置设置并使用Shell脚本上传整个项目代码的最干净方法 更新 更正为 解 正如Fritschy回答的那样,它可以

  • #include <stdio.h> #include <malloc.h> int main(void) { char *p[10]; int i = 0; for (i = 0; i < sizeof(p)/sizeof(p[0]); i++) { p[i] = malloc(100000);