MDQueryGetResultAtIndex和Swift 3中的UnsafeRawPointer

MDQueryGetResultAtIndex和Swift 3中的UnsafeRawPointer,swift,macos,spotlight,Swift,Macos,Spotlight,我在使用MDQuery搜索Swift 3中的聚光灯搜索结果时遇到问题。我希望MDQueryGetResultAtIndex生成一个MDItem,在C/Objective-C中,该假设起作用,我可以调用它上的MDItemCopyAttribute来探索该项。例如,在这里,我成功获取了找到的项目的路径名: MDItemRef item = (MDItemRef)MDQueryGetResultAtIndex(q,i); CFStringRef path = MDItemCopyAttribute(i

我在使用MDQuery搜索Swift 3中的聚光灯搜索结果时遇到问题。我希望
MDQueryGetResultAtIndex
生成一个MDItem,在C/Objective-C中,该假设起作用,我可以调用它上的
MDItemCopyAttribute
来探索该项。例如,在这里,我成功获取了找到的项目的路径名:

MDItemRef item = (MDItemRef)MDQueryGetResultAtIndex(q,i);
CFStringRef path = MDItemCopyAttribute(item,kMDItemPath);
但是在Swift 3中,
MDQueryGetResultAtIndex
返回一个
UnsafeRawPointer(在C中是指向void的指针)。为了克服这个问题,我尝试过,例如:

if let item = MDQueryGetResultAtIndex(q, 0) {
    let ptr = item.bindMemory(to: MDItem.self, capacity: 1)
    let path = MDItemCopyAttribute(ptr.pointee, kMDItemPath)
}
但这会崩溃,日志显示
ptr.pointee
是一个NSAtom。很明显,我的个人魅力不起作用(坦率地说,我总是感到困惑)

如何将这个UnsafeRawPointer转换为可以成功调用的
MDItemCopyAttribute

备选方案

  • 我可以通过将Objective-C代码放入Objective-C帮助对象并从Swift调用它来克服这个困难;但我想写一个纯粹的快速解决方案

  • 类似地,我可能会重写代码以使用更高级别的NSMetadataQuery,我很可能会这样做;但是我最初使用较低级别的MDQueryRef编写的Objective-C代码工作得很好,所以现在我想知道如何将其直接转换为Swift


完成代码对于那些想在家中尝试此功能的人:

let s = "kMDItemDisplayName == \"test\"" // you probably have one somewhere
let q = MDQueryCreate(nil, s as CFString, nil, nil)
MDQueryExecute(q, CFOptionFlags(kMDQuerySynchronous.rawValue))
let ct = MDQueryGetResultCount(q)
if ct > 0 {
    if let item = MDQueryGetResultAtIndex(q, 0) {
        // ... 
    }
}

代码中的问题

if let item = MDQueryGetResultAtIndex(q, 0) {
    let ptr = item.bindMemory(to: MDItem.self, capacity: 1)
    let path = MDItemCopyAttribute(ptr.pointee, kMDItemPath)
}
是指
UnsafeRawPointer
被解释为指向
MDItem
引用,然后在
ptr.pointee
中取消引用,但是 原始指针是
MDItem
引用,因此它被取消引用 一次又一次

将原始指针转换为
MDItem
引用的“最短”方法 是
非安全比特广播

let item = unsafeBitCast(rawPtr, to: MDItem.self)
这是一个(客观的)C型铸造的直接模拟。 您也可以使用这些方法 将原始指针转换为非托管引用并从此处开始 到托管引用(比较):


愚蠢的问题,
item?.assumingmemorybind(to:MDItem.self)?.pointee
获取MDItem?@JAL与
bindMemory
的结果相同。我还尝试将它们一起使用,以防万一。:)啊,好吧,值得一试。我猜你为什么会得到
NSAtom
是因为你的
ptr
正在变成
UnsafePointer(0x1)
,而得到
指针的对象
就相当于调用类似
(id)0x1
的东西,这是一个
\uu NSAtom
。我会继续挖掘。我会假设您必须通过
非托管。fromovaque(…)
–但我不知道
MDQuery
是如何工作的,所以无法测试它。@Hamish我会试试!当然,我也可以发布更多的代码。稍等。“UnsafeRawPointer被解释为指向MDItem引用的指针,然后在
ptr.pointee
中取消引用,但原始指针是MDItem引用”,这是关于何时需要
fromovaque
舞蹈的关键事实,我从未理解过。正如日航在上面的评论中所暗示的那样,CFType被桥接的方式让我在这里绊倒了。回答得好Martin,问得好matt。听起来这个API是一个完美的例子,需要对Swift进行更新。我想我知道@JAL在这里得到了什么。指向void/UnsafeRawPointer的指针背后通常的假设是,我们已经抛弃了指针远端的类型。但是当一个CFTypeRef被插入这里时,正如Martin R所说,它就是指针。这是我到现在为止从未欣赏过的东西。
let item = Unmanaged<MDItem>.fromOpaque(rawPtr).takeUnretainedValue()
import CoreServices

let queryString = "kMDItemContentType = com.apple.application-bundle"
if let query = MDQueryCreate(kCFAllocatorDefault, queryString as CFString, nil, nil) {
    MDQueryExecute(query, CFOptionFlags(kMDQuerySynchronous.rawValue))

    for i in 0..<MDQueryGetResultCount(query) {
        if let rawPtr = MDQueryGetResultAtIndex(query, i) {
            let item = Unmanaged<MDItem>.fromOpaque(rawPtr).takeUnretainedValue()
            if let path = MDItemCopyAttribute(item, kMDItemPath) as? String {
                print(path)
            }
        }
    }
}