Welcome to Day 20 of the 31 Days of iOS. Yesterday, we started discussion how to use maps inside your iOS applications. We reviewed how to display a map, how to show the user’s current location, and how to subscribe to updates that are triggered when the user’s location changed. Lastly, we looked at how to pull the current longitude and latitude out and display it. Today, we’re going to take the next step and go over how to display additional information on the map. This is known an annotating a map and is how you’d handle displaying landmarks, points of interest, or any other information on the map. We’re going to start with the source code from day 19 and add on to it. However, if you’d like to follow along with the completed code, you can access it here.
Handling the UI
As a reminder, if we run our application, it will currently display a map with our location on it. At the top of the application we have the longitude and latitude printed out:
Before we make changes to our actual map, we are going to add a few buttons to our UI so we have something to trigger adding and removing items to the map. Open MainStoryboard.Storyboard and drag two round rect buttons over so they are to the right of the labels. When you’re done, the UI should look like this:
Now switch to the Assistant Editor in the top right of Xcode and control + click and drag from each button to your view controller and create new actions for each button. While we’re editing the ViewController.h file, let’s also set it to implement the MKMapViewDelegate class. When we’re done, our header should look like this:
Now we can implement the annotations.
Before we start adding annotations, we need to set the mapView’s delegate. Switch over to ViewController.m. In the viewDidLoad method, right after setting the showUserLocation property on the mapView we are going to add a line to set the mapView’s delegate to be the ViewController (self):
Now we can implement the Add button to put some annotations on the map.
Today, we’re going to hardcode the location of the annotation we’re going to add to the map. If we wanted to, we could implement the update: Location method to save the current latitude and longitude to a local variable so we could add our annotation at the same point. Alternatively, we could pull a list of longitudes and latitudes from somewhere and use that to put annotations on the map. Since both of those involve the same logic (just replacing how we get the longitude and latitude) we’re going to skip over and just use static values. The first thing we’re going to do is create a new CLLocationCoordinate2D. We’ll set the longitude and latitude properties for this value and then use that to generate a MKPointAnnotation. Finally, this object is passed into the mapView’s addAnotation method. Our tappedAdd method will look like this:
Before we can run our app, we need to implement one method from the MKMapViewDelegate class. This method is the mapView: viewForAnnotation method. This method is called on a map view for any annotations on a map. One thing to consider is that the blue indicator that shows the device’s location is also an annotation and therefore this method is called for it. Since this is where we handle what the annotation will look like, we don’t want to “intercept” the call for the current location indicator. The first thing we’ll do is check and see if the MKAnnotation sent into the method is of the type MKUserLocation. If it is, we just return nil from our method. If not, we continue on and attempt to dequeue a MKPinAnnotationView. If we’re unable to do that, then we generate a new MKPinAnnotationView. We could create our own annotation view but we’re going to use the default which will result in a red pin being dropped on the map. After that, we set properties on the annotation view and return it. The method will end up looking like this:
Now when we run our application and tap the Add button, we should see a pin dropped on the map (the pin is going to show up in Washington state in the United States since we hard coded the location of our annotation):
Since we set the canShowCallout to YES in the mapView: viewForAnnotation method, we can tap on our annotation and see the description and subtitle we had set earlier:
Removing annotations is easy to do by accessing the mapView’s annotations property. We could call the removeAnnotations method on the mapView and passing in the mapView’s annotations property. However, the same issue arises that we saw in the mapView: viewForAnnotation. That being that the user’s location is an annotation on the map view. So instead of calling removeAnnotations and removing an array, we’ll loop through the annotations and remove them if they aren’t a MKUserLocation. Our tappedRemove will look like this:
Now when you run the app and tap Add and then Remove, you should see the annotations go away.
Today we looked at how to add additional information into a map view. This is done by creating annotations and specifying a longitude and latitude that they should appear at. Additionally we looked at how to remove annotations. While we hard coded things like the description and the location of the annotation, you should be able to use this knowledge to handle putting annotations on a map programmatically after pulling the location from the internet or anywhere else. You can download the completed code from today’s walkthrough here.