Apple MapKit Framework

Michael Metzger
6 min readOct 24, 2015

--

I recently dived into the MapKit framework this week and found out how to implement some excellent features that you can use to include in your iOS application. Any functionality that exists on the native Apple Maps app, you can include within your application with completely custom annotations and layers. On this blog, I’ll cover the basics of setting up Maps on a ViewController and how to create annotations. I’ll also show you how to create the annotations in real-time with the MKLocalSearchRequest class.

MapKit framework

The first step is to add the MapKit framework to your application.

In Xcode, go to the build settings and flip the switch for maps to on (pictured above). This will install all of the frameworks that you need. If the installation is successful you’ll also see the file added to your project files on the left hand panel.

Now, go to storyboard and add a ViewController that you want to place the mapkitView on. Note, there is not a MapKitViewController, so you’ll always have to start with a simple ViewController instead. After placing the MapView, be sure to connect it to the delegate of the ViewController class that you are inheriting from. This can be done by simply by control dragging from the mapview to the ViewControler outlet at the top (pictured below). Also, open up the side by side window by clicking on the assistant editor button and connect an IBAction Button along with a UITextField.

Most importantly, add #import <MapKit/MapKit.h>, at the top of the file. This imports all of the mapping methods from the framework that you imported earlier.

Be sure to also add the following protocols to your ViewController.

The MKAnnotation protocol allows you to make changes to the annotations that will be displayed on the map, while the MKMapViewDelegate is what we connected our mapView to on the StoryBoard earlier.

Live Map Search

Adding live search capability to your map is easy. Go to your ViewController.m file and add the following code at the top of your file.

The placeMarks, array will be our local storage for our locations from the live search. There is no need for a mutable array here since it will only exist once during the runtime of the ViewController.m file. We are not going to use these locations anymore after a single execution. Don’t worry if that doesn’t make sense now, as it will be more clear when you finish and run the app.

MKLocalSearch, is our locally declared object that initiates the map search operation. This is used for only one search at at time.

Search Action Button

When the user clicks the search button after entering their text we need to execute the search operation. In the same ViewController.m file, find the — (IBAction)searchButton:(id)sender {} method and place the code below in the brackets.

First, we create an instance of MKLocalSearchRequest. This will be our object that we pass the naturalLanguageQuery object too. naturalLanguageQuery is also set equal to searchTextField. Remember that searchTextField is where the user inputs the text that they want to search. At this point, the code written, takes the user input, translates it to a string and then set’s that to region.naturalLanguageQuery, which converts the user text into a searchable string that the MKLocalSearch class can handle. We then tell the request object what region to conduct the search. This region is set to wherever the user is zoomed into on the mapView outlet. For example, if they were zoomed into New York City, then the search will only be conducted within that visible area.

Next, we create a MKLocalSearchCompletionHandler block. This is the part of the code that will be executed last. This is where the actual search will be initiated. Inside this block, the placeMarks array will be initialized and loaded with all the the result objects. After the array is complete, two separate ViewDidLoad methods are started (I’ll go over these later).

Finally, the localSearch property that we created at the top of the ViewController.m file is initialized and passed the completionHandler block once the search is complete. [self.view endEditing:YES]; just removed the keyboard out of the users way.

Adding Annotations to the Map

Now, that we have an array with the returned search results, we need to convert those to pins on the map. Create a new file named MapViewAnnotation and make it a subclass of NSObject.

This is going to be our class that will hold our properties for creating annotations. Refer to the image below and #import the MapKit framework and add the MKAnnotation protocol.

Now, go back to your ViewController class and import the MapViewAnnotation class. Then, add the following code:

We use the viewDidAppear: method instead of viewDidLoad because viewDidLoad was executed right when the ViewController was first launched. Within this method, we loop for the searched items in the array and create MapViewAnnotation objects. The names, location, and title, properties are added to the annotation objects. Finally, the annotations are added to the maps.

If you run the app now, pins will appear on the map, but when you search again, the old pins will remain. To clear the old pins out, we will use the viewDidDisappear: method.

This method, initiates at the same time as ViewDidAppear and clears out the old pins for the new one.

Customizing the Annotations further

At this point, our application is fully functional, but we can customize the annotations further. This is done through the viewForAnnotation method. Add the following code to your viewController.m file:

This method works similar to the cellForRowAtIndexPath method in a table view. Like a tableView, we are reusing the map annotations with a deueueReusable method. Within the method we first create an instance of MKAnnotationView and the assign it an identifier. Then all the annotations that are on the map are converted with the identifier. We then enable the custom annotation and the ability to show a callout.

A callout is an extra tab that appears on within the map pin detail.

After, I enabled the callout, I programmatically created a UIButton and then assigned it to the right hand side of the tab with the rightCalloutAccessoryView method. I also assigned the button to the -(void)button method by using the @selector within the UIButton creation and attributing it to the button method.

At this point you should have a functioning map with a callout buttons applied to the pins after the search. When you click the callout, you should get the “button pressed” log in the console.

--

--