Swift UnsafeMutablePointer <Unmanaged <CFString>?>分配和打印

 LINBO-D_915 发布于 2022-12-09 14:02

我是swift的新手,我在处理非托管CFString(或NSString)的指针时遇到了一些困难.我正在研究一个暗示使用UnsafeMutablePointer?>的CoreMIDI项目,你可以在这个函数中看到:

func MIDIObjectGetStringProperty(_ obj: MIDIObjectRef,
                           _ propertyID: CFString!,
                           _ str: UnsafeMutablePointer?>) -> OSStatus

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

目前我写了这个:

// Get the first midi source (I know it exists)
var midiEndPoint : Unmanaged = 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?>(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,而且很快就有很多不同之处.

编辑:

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

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

'Unmanaged'中的结果不能转换为'MIDIObjectRef'.所以我添加了一个"&",因为MIDIObjectRef是一个UnsafeMutablePointer .

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

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

var midiEndPoint = MIDIGetSource(0)
var property : Unmanaged?
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?
        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定义.当我在旧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位设备......

谢谢你的宝贵帮助

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服务参考中有说明:

    注意

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

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

    有关详细信息,请参阅" 使用Cocoa数据类型"中的 "非托管对象" .

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

    2022-12-11 02:11 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有