mhu*_*ron 5 macos cocoa finder swift
我正在尝试检索所有可用 Finder 标签的列表。
我发现NSWorkspace().fileLabels,它确实返回一个数组,但只返回一个标签颜色数组,而不是标签本身:
print(NSWorkspace.shared().fileLabels) // prints ["None", "Gray", "Green", "Purple", "Blue", "Yellow", "Red", "Orange"]
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它甚至不是所有的默认标签,它缺少Home、Work和Important,而且显然没有我创建的任何自定义标签。看起来它只是与 fileLabelColors 搭配的好名字。
我发现 NSMetadataQuery 用于实际搜索,但是如何获取我在 Finder 中创建的所有标签的列表?
在使用“Hopper Disassembler”和我自己的“Find Any File”(用于文件中的文本搜索)进行一些挖掘之后,我找出了自蒙特雷以来标签现在存储的位置:
该文件~/Library/SyncedPreferences/com.apple.kvs/com.apple.KeyValueService-Production.sqlite包含与之前存储在~/Library/SyncedPreferences/com.apple.finder.plist.
但它现在隐藏在数据库记录中:
如果您查看 ZSYSDMANAGEDKEYVALUE 表,您将发现一个带有 ZKEY="FinderTagDict" 的条目。ZPLISTDATAVLUE 包含一个 bplist 记录,其中包含 pblist(二进制 plist)结构,您可以从中提取标签。
NSWorkspace.shared().fileLabels仅返回创建用户帐户时可用的系统标签(默认系统标签)。
遗憾的是,macOS 中没有 API 可以检索您在 Finder 中自行创建的标签。
解决方案是解析~/Library/SyncedPreferences/com.apple.finder.plist:
func allTagLabels() -> [String] {
// this doesn't work if the app is Sandboxed:
// the users would have to point to the file themselves with NSOpenPanel
let url = URL(fileURLWithPath: "\(NSHomeDirectory())/Library/SyncedPreferences/com.apple.finder.plist")
let keyPath = "values.FinderTagDict.value.FinderTags"
if let d = try? Data(contentsOf: url) {
if let plist = try? PropertyListSerialization.propertyList(from: d, options: [], format: nil),
let pdict = plist as? NSDictionary,
let ftags = pdict.value(forKeyPath: keyPath) as? [[AnyHashable: Any]]
{
return ftags.flatMap { $0["n"] as? String }
}
}
return []
}
let all = allTagLabels()
print(all)
Run Code Online (Sandbox Code Playgroud)
这将获取所有Finder 标签。
您还可以仅选择自定义标签(忽略系统标签):
func customTagLabels() -> [String] {
let url = URL(fileURLWithPath: "\(NSHomeDirectory())/Library/SyncedPreferences/com.apple.finder.plist")
let keyPath = "values.FinderTagDict.value.FinderTags"
if let d = try? Data(contentsOf: url) {
if let plist = try? PropertyListSerialization.propertyList(from: d, options: [], format: nil),
let pdict = plist as? NSDictionary,
let ftags = pdict.value(forKeyPath: keyPath) as? [[AnyHashable: Any]]
{
return ftags.flatMap { tag in
if let n = tag["n"] as? String,
tag.values.count != 2
{
return n
}
return nil
}
}
}
return []
}
Run Code Online (Sandbox Code Playgroud)