Searching on a Map View in iOS8 with Swift

Using the MKLocalSearchRequest. object type, it is possible to provide a search query. The response can then be manipulated. In this tutorial we will search for Hotels and Musea in the city of Amsterdam. The results of the search will be displayed on the map by using annotations. This tutorial is built in iOS 8.3 with Xcode 6.3

Open Xcode and create a new Single View Application. For product name, use IOS8SwiftSearchMapTutorial and then fill out the Organization Name and Organization Identifier with your customary values. Enter Swift as Language and make sure only iPhone is selected in Devices.

Go to the Project Settings and select the Capabilities tab. Turn the Maps Capabilities on to link the MapKit framework to the project.

Go to the Storyboard and drag a MapKit View to the main view. Select the MapKit View and go to the Size Inspector, enter the following values. 

Also drag a Segmented Control to the main View and place it below the MapKit View. Double-click to change the predefined titles into "Hotel" and "Museum". The Storyboard will look like this.

While holding the Ctrl key select both the Map View and the Segmented Control. Select "Resolve Auto Layout Issues" button  to the bottom-right of the Storyboard and choose "Add Missing Constraints". 

Select the Assistant Editor and make sure the ViewController.swift file is visible. Ctrl and drag from the Map View to the ViewController class and create the following Outlet.

Ctrl and drag from the Segmented Control to the ViewController class and create the following Outlet.

Finally, Ctrl and drag from the Segmented Control to the ViewController class and create the following Action.

Go to the ViewController.swift file and at the top of the file import the MapKit framework.

import MapKit

We would like to search an area for Hotels and Musea, so we pick the city of Amsterdam as our location. Add the following property constants the ViewController class.

let initialLocation = CLLocation(latitude: 52.3740300, longitude: 4.8896900)
let searchRadius: CLLocationDistance = 2000

The search radius is set to 2000 metres. Change the viewDidLoad method to

override func viewDidLoad() {

    let coordinateRegion = MKCoordinateRegionMakeWithDistance(initialLocation.coordinate, searchRadius * 2.0, searchRadius * 2.0)
    mapView.setRegion(coordinateRegion, animated: true)

The coordinateRegion variable is created fromm the initial coordinate, with a latitiude and longitude twice the value of the searchRadius. This region is then set and made visible in the Map View. Build and Run the project to see the visible Region.

To search inside a Map View a new searchInMap() method is created.

func searchInMap() {
    // 1
    let request = MKLocalSearchRequest()
    request.naturalLanguageQuery = segmentedControl.titleForSegmentAtIndex(segmentedControl.selectedSegmentIndex)
    // 2    
    let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1) 
    request.region = MKCoordinateRegion(center: initialLocation.coordinate, span: span) 
    // 3
    let search = MKLocalSearch(request: request) 
    search.startWithCompletionHandler {
        (response: MKLocalSearchResponse!, error: NSError!) in
        for item in response.mapItems as! [MKMapItem] {
            println("Item name = \(")
            println("Latitude = \(item.placemark.location.coordinate.latitude)")
            println("Longitude = \(item.placemark.location.coordinate.longitude)")
  1.  a MKLocalSearchRequest object is created, which can be used to specify search parameters. The search query equals to the title of the currently selected index of the segmented control.
  2. The region on which the search will be applied is defined.
  3. a MKLocalSearch object initiates a search operation and will deliver the results back into an array of MKMapItems. This will contain the name, latitude and longitude of the current POI. 

Add the following line to the end of the viewDidLoad method to call the searchinMap method


Build and Run the project again. The Item name, latitude and longitude of the found items in the area will be printed to the console. These results must appear inside the Map by using an annotation. Create a New File -> iOS -> Source -> Cocoa Touch Class. Name the class MyAnnotation and make it a subclass of NSObject.

Change the MyAnnotation.swift file to

import UIKit
import MapKit

class MyAnnotation: NSObject, MKAnnotation {
    var coordinate: CLLocationCoordinate2D = CLLocationCoordinate2DMake(0, 0)
    var title: String!
    init(coordinate: CLLocationCoordinate2D, title: String) {
        self.coordinate = coordinate
        self.title = title

The class conforms to the MKAnnotation protocol, which will send the object data to the Map View. Here we declare two properties, coordinate and title. The annotation must be assigned to the current Map View. In ViewController.swift add the following method

func addPinToMapView(title: String, latitude: CLLocationDegrees, longitude: CLLocationDegrees) {
        let location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
        let annotation = MyAnnotation(coordinate: location, title: title)

This will add the pin  including the annotation to the map. In the searchMap method inside the for in loop delete the println lines and add the following line

self.addPinToMapView(, latitude: item.placemark.location.coordinate.latitude, longitude: item.placemark.location.coordinate.longitude)

Build and Run the project, the pins will be displayed on the map. In the current state the pins will be displayed even if we change the value in the segmented control. Change the searchOnValueChanged method.

 @IBAction func searchOnValueChanged(sender: AnyObject) {

The currently displayed annotations will be removed, and the new annotations will be displayed. Build and Run the project view the pins including the annotations.

You can download the source code of the IOS8SwiftSearchMapTutorial at the ioscreator repository on Github.