Intermediate iOS 15 Programming with Swift

Chapter 9
Search for Nearby Points of Interest Using Local Search

The Search API (i.e MKLocalSearch) allows iOS developers to search for points of interest and display them on maps. App developers can use this API to perform searches for locations, which can be name, address, or type, such as coffee or pizza.

The use of MKLocalSearch is very similar to the MKDirections API covered in the previous chapter. You'll first need to create an MKLocalSearchRequest object that bundles your search query. You can also specify the map region to narrow down the search result. You then use the configured object to initialize an MKLocalSearch object and perform the search.

The search is performed remotely in an asynchronous way. Once Apple returns the search result (as an MKLocalSearchResponse object) to your app, the complete handler will be executed. In general, you'll need to parse the response object and display the search results on the map.

Local Search Demo App

There is no better way to understand local search than working on a demo project. Again we will not start from scratch but build on top of the previous project to add a Nearby feature. When you tap the Nearby button, the app searches for nearby restaurants and pins the places on the map.

To start with, first download the Xcode project template from http://www.appcoda.com/resources/swift55/LocalSearchStarter.zip. Unzip it and open the MapKitDirection project.

Note: The starter project is exactly the same as the final project of the MapKit Direction demo.

Adding a Nearby Button in Storyboard

Okay, let's get started. First, go to Main storyboard and add a button item to the map view. Set the image of the button to face.smiling. After that, add the spacing and size constraints. When tapped, this button will show the nearby restaurants. From now and onwards, I refer this button as the Nearby button.

Figure 9.1. Adding a Nearby button to the map view controller
Figure 9.1. Adding a Nearby button to the map view controller

Search Nearby Restaurants and Adding annotations

Once you added the button, open the MapViewController.swift file. We will create an action method called showNearby for the Nearby button. In the implementation, we will search for nearby restaurants and pin the results on the map.

Insert the following code snippet in the class:

@IBAction func showNearby(sender: UIButton) {
    let searchRequest = MKLocalSearch.Request()
    searchRequest.naturalLanguageQuery = restaurant.type
    searchRequest.region = mapView.region

    let localSearch = MKLocalSearch(request: searchRequest)
    localSearch.start { (response, error) -> Void in
        guard let response = response else {
            if let error = error {
                print(error)
            }

            return
        }

        let mapItems = response.mapItems
        var nearbyAnnotations: [MKAnnotation] = []
        if mapItems.count > 0 {
            for item in mapItems {
                // Add annotation
                let annotation = MKPointAnnotation()
                annotation.title = item.name
                annotation.subtitle = item.phoneNumber
                if let location = item.placemark.location {
                    annotation.coordinate = location.coordinate
                }
                nearbyAnnotations.append(annotation)
            }
        }

        self.mapView.showAnnotations(nearbyAnnotations, animated: true)
    }
}

To perform a local search, here are the two things you need to do:

  • Specify your search parameters in an MKLocalSearch.Request object. You are allowed to specify the search criteria in natural language by using the naturalLanguageQuery parameter. For example, if you want to search for a nearby cafe, you can specify cafe in the search parameter. Since we want to search for similar types of restaurants, we specify restaurant.type in the query.
  • Initiate the local search by creating an MKLocalSearch object with the search parameters. An MKLocalSearch object is used to initiate a map-based search operation and delivers the results back to your app asynchronously.

In the showNearby method, we lookup the nearby restaurants that are of the same type (e.g. Italian). Furthermore, we specify the current region of the map view as the search region.

We then initialize the search by creating the MKLocalSearch object and invoking the start(completionHandler:) method. When the search completes, the closure will be called and the results are delivered as an array of MKMapItem. In the body of the closure, we loop through the items (i.e. nearby restaurants) and highlight them on the map using annotations. To pin multiple annotations on maps, you call the showAnnotations method and pass it the array of MKAnnotation objects to pin.

Okay, you're almost ready to test the app. Just go to the storyboard and connect the Nearby button with the showNearby method. Simply control-drag from the Nearby button to the view controller icon in the scene dock and select the showNearbyWithSender: action method.

Figure 9.2. Associating the action method with the Nearby button
Figure 9.2. Associating the action method with the Nearby button

Testing the Demo App

Now hit the Run button to compile and run your app. Select a restaurant to bring up the map view. Tap the Nearby button and the app should show you the nearby restaurants.

Figure 9.3. The demo app now shows nearby restaurants
Figure 9.3. The demo app now shows nearby restaurants

Cool, right? With just a few lines of code, you took your Map app to the next level. If you're going to embed a map within your app, try to explore the local search API.

For reference, you can download the complete Xcode project from http://www.appcoda.com/resources/swift55/LocalSearch.zip.