swift - Swift 3 中的 MDQueryGetResultAtIndex 和 UnsafeRawPointer

标签 swift macos spotlight

我在使用 MDQuery 浏览 Swift 3 中的 Spotlight 搜索结果时遇到了问题。我希望 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 mojo 不起作用(坦率地说,我一直觉得这很困惑)。

我如何将这个 UnsafeRawPointer 转换成我可以成功调用 MDItemCopyAttribute 的东西?

备选方案

  • 我可以通过将我的 Objective-C 代码放入一个 Objective-C 辅助对象并从 Swift 调用它来克服这个障碍;但我想编写一个纯 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 引用的“最短”方法 是 unsafeBitCast:

let item = unsafeBitCast(rawPtr, to: MDItem.self)

这是 (Objective-)C 转换的直接模拟。 您还可以使用 Unmanaged方法 将原始指针转换为非托管引用并从那里 到托管引用(比较 How to cast self to UnsafeMutablePointer<Void> type in swift ):

let item = Unmanaged<MDItem>.fromOpaque(rawPtr).takeUnretainedValue()

这看起来有点复杂,但也许表达了意图 更清楚。后一种方法也适用于 (+1) 保留 引用(使用 takeRetainedValue())。

独立示例:

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

关于swift - Swift 3 中的 MDQueryGetResultAtIndex 和 UnsafeRawPointer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43478800/

相关文章:

ios - 预编译器条件编译两种情况

swift - 了解 Realm 对象服务器上的用户

objective-c - cocoa ffmpeg 流创建了不正确的文件

cocoa - Spotlight NSMetaDataQuery 与不可见项目不会自动更新

Three.js: mesh 不接收阴影,不被 intersectObjects 检测到

ios - Swift 4 - 在我的 RESTful API 调用中是 "Background Thread?"

json - Alamofire 奇怪的 JSON 前缀 - Swift 2.0

swift - 如何知道背景中的窗口何时成为最前面的窗口?

objective-c - 从 `username` 给出的 `SecKeychainItemRef` 中提取 `SecKeychainFindGenericPassword` ?

dynamic - 如何更改 THREE.js 中的 SpotLight ShadowCameraNear 参数?