Swift 3 中的 MDQueryGetResultAtIndex 和 UnsafeRawPointer
MDQueryGetResultAtIndex and UnsafeRawPointer in Swift 3
我在使用 MDQuery 浏览 Swift 3 中的 Spotlight 搜索结果时遇到问题。我希望 MDQueryGetResultAtIndex
产生一个 MDItem,并且在 C/Objective-C 中,该假设有效,我可以对其调用 MDItemCopyAttribute
来探索该项目。在这里,例如,我成功获取了找到的项目的路径名:
MDItemRef item = (MDItemRef)MDQueryGetResultAtIndex(q,i);
CFStringRef path = MDItemCopyAttribute(item,kMDItemPath);
但是在 Swift 3 中,MDQueryGetResultAtIndex
returns 一个 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,我可能会这样做;但是我原来的 Objective-C 代码使用较低级别的 MDQueryRef 工作正常,所以现在我很好奇如何将它直接变成 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
引用的"shortest"方法
是 unsafeBitCast
:
let item = unsafeBitCast(rawPtr, to: MDItem.self)
这是 (Objective-)C 演员表的直接模拟。
您还可以使用 Unmanaged
方法
将原始指针转换为非托管引用并从那里
到托管引用(比较 ):
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)
}
}
}
}
我在使用 MDQuery 浏览 Swift 3 中的 Spotlight 搜索结果时遇到问题。我希望 MDQueryGetResultAtIndex
产生一个 MDItem,并且在 C/Objective-C 中,该假设有效,我可以对其调用 MDItemCopyAttribute
来探索该项目。在这里,例如,我成功获取了找到的项目的路径名:
MDItemRef item = (MDItemRef)MDQueryGetResultAtIndex(q,i);
CFStringRef path = MDItemCopyAttribute(item,kMDItemPath);
但是在 Swift 3 中,MDQueryGetResultAtIndex
returns 一个 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,我可能会这样做;但是我原来的 Objective-C 代码使用较低级别的 MDQueryRef 工作正常,所以现在我很好奇如何将它直接变成 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
引用的"shortest"方法
是 unsafeBitCast
:
let item = unsafeBitCast(rawPtr, to: MDItem.self)
这是 (Objective-)C 演员表的直接模拟。
您还可以使用 Unmanaged
方法
将原始指针转换为非托管引用并从那里
到托管引用(比较
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)
}
}
}
}