iOS 9 App Search Tutorial: Introduction to App Search

Discover how easy it is to make your app’s content searchable through Spotlight with this iOS 9 app search tutorial. By Chris Wagner.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 3 of this article. Click here to view the first page.

Opening search results

The ideal user experience is to launch the app directly to the relevant content without any fanfare. In fact — it’s a requirement — Apple uses the speed at which your app launches and displays useful information as one of the metrics to rank search results.

In the previous section, you laid the groundwork for this by providing both an activityType and a userInfo object for your NSUserActivity instances.

Open AppDelegate.swift and add this empty implementation of application(_:continueUserActivity:restorationHandler:) below application(_:didFinishLaunchingWithOptions:):

func application(application: UIApplication,
  continueUserActivity userActivity: NSUserActivity,
  restorationHandler: ([AnyObject]?) -> Void) -> Bool {

  return true
}

When a user selects a search result, this method is called — it’s the same method that’s called by Handoff to continue an activity from another device.

Add the following logic above return true in application(_:continueUserActivity:restorationHandler:):

guard userActivity.activityType == Employee.domainIdentifier,
  let objectId = userActivity.userInfo?["id"] as? String else {
    return false
}

This guard statement verifies the activityType is what you defined as an activity for Employees, and then it attempts to extract the id from userInfo. If either of these fail, then the method returns false, letting the system know that the activity was not handled.

Next, below the guard statement, replace return true with the following:

if let nav = window?.rootViewController as? UINavigationController,
  listVC = nav.viewControllers.first as? EmployeeListViewController,
  employee = EmployeeService().employeeWithObjectId(objectId) {
    nav.popToRootViewControllerAnimated(false)

    let employeeViewController = listVC
      .storyboard?
      .instantiateViewControllerWithIdentifier("EmployeeView") as!
        EmployeeViewController

    employeeViewController.employee = employee
    nav.pushViewController(employeeViewController, animated: false)
    return true
}

return false

If the id is obtained, your objective is to display the EmployeeViewController for the matching Employee.

The code above may appear a bit confusing, but think about the app’s design. There are two view controllers, one is the list of employees and the other shows employee details. The above code pops the application’s navigation stack back to the list and then pushes to the specific employee’s details view.

If for some reason the view cannot be presented, the method returns false.

Okay, time to build and run! Select Cary Iowa from the employees list, and then go to the home screen. Activate Spotlight and search for Brent Reid. When the search result appears, tap it. The app will open and you’ll see it fade delightfully from Cary to Brent. Excellent work!

Deleting items from the search index

Back to the premise of your app. Imagine that an employee was fired for duct taping the boss to the wall after a particularly rough day. Obviously, you won’t contact that person anymore, so you need to remove him and anybody else that leaves the company from the Colleagues search index.

For this sample app, you’ll simply delete the entire index when the app’s indexing setting is disabled.

Open EmployeeService.swift and add the following import statement at the top of the file.

import CoreSpotlight

Next, find destroyEmployeeIndexing(). Replace the TODO with the following logic:

CSSearchableIndex
  .defaultSearchableIndex()
  .deleteAllSearchableItemsWithCompletionHandler { error in
  if let error = error {
    print("Error deleting searching employee items: \(error)")
  } else {
    print("Employees indexing deleted.")
  }
}

This single parameterless call destroys the entire indexed database for your app. Well played!

Now to test out the logic; perform the following test to see if index deletion works as intended:

  1. Build and run to install the app.
  2. Stop the process in Xcode.
  3. In the simulator or on your device, go to Settings \ Colleagues and set Indexing to Viewed Records.
  4. Open the app again and select a few employees so that they are indexed.
  5. Go back to the home screen and activate Spotlight.
  6. Search for one of the employees you viewed and verify the entry appears.
  7. Go to Settings \ Colleagues and set Indexing to Disabled.
  8. Quit the app.
  9. Reopen the app. This will purge the search index.
  10. Go to the home screen and activate Spotlight.
  11. Search for one of the employees you viewed and verify that no results appear for the Colleagues app.

So deleting the entire search index was pretty easy, huh? But what if you want to single out a specific item? Good news — these two APIs give you more fine-tuned control over what is deleted:

  • deleteSearchableItemsWithDomainIdentifiers(_:completionHandler:) lets you delete entire “groups” of indexes based on their domain identifiers.
  • deleteSearchableItemsWithIdentifiers(_:completionHandler:) allows you work with individual records using their unique identifiers.

This means that globally unique identifiers (within an app group) are required if you’re indexing multiple types of records.

Note: If you can’t guarantee uniqueness across types, like when replicating a database that uses auto-incrementing IDs, then a simple solution could be to prefix the record’s ID with its type. For example, if you had a contact object with an ID of 123 and an order object with an ID of 123, you could set their unique identifiers to contact.123 and order.123 respectively.

If you’ve run into any issues you can download the completed project here.

Where to go from here?

This iOS 9 app search tutorial has covered iOS 9’s simple yet powerful approach to indexing the content inside your app using user activities. Searching isn’t limited to content though — you can also use it to index navigation points within an app.

Consider a CRM app that has multiple sections such as Contacts, Orders and Tasks. By creating user activities whenever a user lands on one of these screens, you’d make it possible for them to search for Orders and be directly to that section of your app. How powerful would this be if your app has many levels of navigation?

There are many unique ways to bubble up content to your users. Think outside the box and remember to educate your users about this powerful function.

This tutorial was an abbreviated version of Chapter 2, “Introducing App Search” from iOS 9 by Tutorials. If you’d like to learn about indexing large data sets with Core Spotlight or web content with iOS 9 please check out the book!

Chris Wagner

Contributors

Chris Wagner

Author

Over 300 content creators. Join our team.