swiftfoundationspotlight

How to do a Spotlight search in Swift (NSMetadataQuery)?


I'm trying to do a Spotlight search inside a mac app. Here is the code I have so far:

import Foundation

let nf = NotificationCenter.default

class FileSearcher {

  public static let sharedInstance = FileSearcher()
  
  var query: NSMetadataQuery? {
    willSet {
      if let q = self.query {
        q.stop()
      }
    }
  }

  init() {
    print("Setting observer")
    nf.addObserver(forName: .NSMetadataQueryDidStartGathering, object: nil, queue: .main, using: {_ in

      print("Query did start gathering")
    })

    nf.addObserver(forName: .NSMetadataQueryDidUpdate, object: nil, queue: .main, using: {_ in

      print("QUery results updated \(self.query?.resultCount)")
    })
    nf.addObserver(forName: .NSMetadataQueryDidFinishGathering, object: nil, queue: .main, using: {_ in
      print("Got results \(self.query?.results)")
    })
  }


  func searchFile(_ oq: String) {
    print("Searching \(oq)")
    query = NSMetadataQuery()
    let predicate = NSPredicate(format: "%K ==[cd] %@", NSMetadataItemFSNameKey ,oq)
    query?.searchScopes = [NSMetadataQueryIndexedLocalComputerScope]
    query?.predicate = predicate
    query?.start()
  }
}


The problem is the query did update and query did finish gathering are never triggered. Maybe it has to do something with my predicate? I'm trying to do a fuzzy search.

Any help is much appreciated!


Solution

  • Found the problem, which was not mentioned in any of the Stack Overflow answers I saw and apparently it is documented somewhere. You need to call it from the main dispatch queue:

    func searchFile(_ oq: String) {
        if(!oq.isEmpty) {
          query = NSMetadataQuery()
          let predicate = NSPredicate(format: "%K ==[cd] %@", NSMetadataItemFSNameKey, oq)
          query?.searchScopes = [NSMetadataQueryIndexedLocalComputerScope]
          query?.predicate = predicate
          DispatchQueue.main.async {
            self.query?.start()
          }
        }
      }