I am trying to get some data back from Core Spotlight which I am storing using a custom attribute key. Tested this on macOS and iOS as well, the result is always the same.
My test class:
import CoreSpotlight
class SpotlightSearch {
let domainId = "com.company.some"
let originalDataKeyName: String
init() {
self.originalDataKeyName = domainId.replacingOccurrences(of: ".", with: "_") + "_originalData"
}
func addToIndex(title: String, content: String) {
guard let originalDataKey = CSCustomAttributeKey(keyName: originalDataKeyName, searchable: false, searchableByDefault: false, unique: false, multiValued: false)
else { return }
let uniqueId = "MyUniqueId" + title
let originalContent = NSString(string: content)
let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeText as String)
attributeSet.title = title
attributeSet.setValue(originalContent, forCustomKey: originalDataKey)
let item = CSSearchableItem(uniqueIdentifier: uniqueId, domainIdentifier: domainId, attributeSet: attributeSet)
CSSearchableIndex.default().indexSearchableItems([item]) { error in
if let error = error {
print("Indexing error: \(error.localizedDescription)")
} else {
print("Item '\(title)' successfully indexed!")
}
}
}
var query: CSSearchQuery?
func search(title: String) {
var allItems = [CSSearchableItem]()
let queryString = "title == '\(title)'cd"
let attributes = [ "title", originalDataKeyName ]
let newQuery = CSSearchQuery(queryString: queryString, attributes: attributes)
newQuery.foundItemsHandler = { (items: [CSSearchableItem]) -> Void in
allItems.append(contentsOf: items)
}
newQuery.completionHandler = { [weak self] (error: Error?) -> Void in
guard let originalDataKeyName = self?.originalDataKeyName,
let originalDataKey = CSCustomAttributeKey(keyName: originalDataKeyName)
else { return }
print("Search complete")
for item in allItems {
let attributeSet = item.attributeSet
let customData = attributeSet.value(forCustomKey: originalDataKey)
// Always nil
if customData == nil {
print("\(String(describing: originalDataKeyName)) not found in \(attributeSet.description)")
} else if let originalData = customData as? NSData {
let data = Data(referencing: originalData)
if let originalString = String(data: data, encoding: .utf8) {
print("Found '\(originalString)'")
}
}
}
}
query = newQuery
newQuery.start()
}
}
On app init:
let newSpotlightSearch = SpotlightSearch()
newSpotlightSearch.addToIndex(title: "Banana", content: "π")
Later:
spotlightSearch.search(title: "Banana")
It will find the title, but will not give me back the custom attribute value. If I put a breakpoint after "// Always nil" and use po attributeSet I will get
(lldb) po attributeSet
{
"_kMDItemBundleID" = "de.axelspringer.SearchMac";
"_kMDItemDomainIdentifier" = "com.company.some";
"_kMDItemExpirationDate" = "2018-08-26 00:00:00 +0000";
"_kMDItemExternalID" = MyUniqueIdBanana;
"com_company_some_originalData" = "\Ud83c\Udf4c";
kMDItemTitle = Banana;
}
So the value is there, but Spotlight will not return it to me. Already tried to use NSData instead of NSString for the custom attribute, but same result.
Also found this orphaned question in the Apple developer forums:
CSCustomAttributeKey
insearch(:)
as you do inaddToToIndex(::)
? So either use the long version (CSCustomAttributeKey(keyName: originalDataKeyName, searchable: false, searchableByDefault: false, unique: false, multiValued: false)
) or the short one (CSCustomAttributeKey(keyName: originalDataKeyName)
) in both places, β Footton