Monday, 30 July 2018

How to get custom value back from Spotlight with CSCustomAttributeKey

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 valueForCustomKey not working



from How to get custom value back from Spotlight with CSCustomAttributeKey

No comments:

Post a Comment