blog

Photo by tyler hendy from Pexels

Searching App Content with Core Spotlight

by

In the first part of this series of posts about Core Spotlight we looked at how to use the Core Spotlight APIs to index application data, how to search that data using Spotlight, and how to respond when a user selects a search result for your application’s data. In this post we’ll take a look at how easy it can be to search that same index from within your app. The demo app has been updated and is still available on GitHub.

Using CSSearchQuery to Search the Spotlight Index

In iOS 10 Apple introduced the CSSearchQuery class that allows us to search the same Spotlight index from within our app that we relied on in the first post when searching from the iOS Spotlight search field. The class is straightforward to use – you basically:

  1. Define the query using the straightforward search query syntax.
  2. Define handler blocks that are called when items are found or the search has completed.
  3. Start the search.

In the searchFor: method below, extracted from the AirportsViewController class of the demo app, you can see this process in action.

At the moment, it’s not possible to update an existing query so in the demo app as the user enters text into the search field we cancel any existing queries and create a new one with each change made to the search query. Despite that, if you’re taking advantage of Core Spotlight to index content within your app, the CSSearchQuery API makes it trivial to search that content, and is worth checking out in iOS 10.

search.m

- (void)searchFor:(NSString*)query
{
   // Cancel any existing search queries
   if (self.searchQuery)
   {
      [self.searchQuery cancel];
      self.searchQuery = nil;
      [self.searchResults removeAllObjects];
      [self updateSearchResults];
   }
   // Create the query
   NSString* queryString = [NSString stringWithFormat:@"displayName == '*%@*'c", query];
   self.searchQuery = [[CSSearchQuery alloc] initWithQueryString:queryString
                                                      attributes:@[@"displayName"]];
   __weak typeof(self) weakSelf = self;
   // When items are found, add them to the search results
   self.searchQuery.foundItemsHandler = ^(NSArray<CSSearchableItem *> *items) {
      for (CSSearchableItem* item in items)
      {
         ALAirport* airport = [weakSelf.airportController
                               airportWithIdentifier:[item uniqueIdentifier]];
         [weakSelf.searchResults addObject:airport];
         [weakSelf updateSearchResults];
      }
   };
   // When complete, update the search results
   self.searchQuery.completionHandler = ^(NSError* error) {
      if (error)
      {
         NSLog(@"%@", error);
      }
      else
      {
         [weakSelf updateSearchResults];
      }
   };
   // Start the search. Handle results and errors using the handler blocks
   [self.searchQuery start];
}

Header image by Aidan Gibbons, licensed under Creative Commons

+ more

Accurate Timing

Accurate Timing

In many tasks we need to do something at given intervals of time. The most obvious ways may not give you the best results. Time? Meh. The most basic tasks that don't have what you might call CPU-scale time requirements can be handled with the usual language and...

read more