MapKit Tutorial: Getting Started

Learn to use the powerful MapKit framework to build an interactive map, displaying location details and launching Maps for driving directions. By Andrew Tetlaw.

4.8 (34) · 4 Reviews

Download materials
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

Plotting the Artwork

You now have an array of all the public artwork in the dataset, which you’ll add to the map.

Still in ViewController.swift, add the following code at the end of viewDidLoad():

loadInitialData()
mapView.addAnnotations(artworks)
Note: Be sure to use the plural addAnnotations, not the singular addAnnotation!

Delete the lines that create the single King David Kalakaua map annotation. You don’t need them now that loadInitialData() creates the artworks array.

Build and run. Check out all the markers!

Map with many pins showing art locations.

Move the map around to see other markers appear. Tap a marker to open its callout bubble, then tap its info button to launch the Maps. Yes, everything you did with the King Kalakaua statue works with all the new artwork as well!

If you’re worried about adding annotations to the map when they’re not visible, don’t be! Apple recommends adding all the annotations right away, whether or not they’re visible in the map region. When you move the map, it automatically displays the visible annotations.

And that’s it! You’ve built an app that parses a GeoJSON file into an array of artworks, then displays them as annotation markers, with a callout info button that launches Maps. Celebrate with a hula dance around your desk! :]

But wait, there are still a few bits of bling to add.

Customizing Annotations

Remember the discipline property in the Artwork class? Its values are things like Sculpture and Mural. In fact, the most numerous disciplines are Sculpture, Plaque, Mural and Monument.

It’s easy to color-code the markers, so the most numerous disciplines each have their own colored marker, and all the other disciples have green markers.

Markers with Color-Coding and Text

In Artwork.swift, add this property:

var markerTintColor: UIColor  {
  switch discipline {
  case "Monument":
    return .red
  case "Mural":
    return .cyan
  case "Plaque":
    return .blue
  case "Sculpture":
    return .purple
  default:
    return .green
  }
}

Now, you could keep adding code to mapView(_:viewFor:), but that would clutter the view controller. There’s a more elegant way, similar to what you can do for table view cells. Create a new Swift file named ArtworkViews.swift and add this code, below the import statement:

import MapKit

class ArtworkMarkerView: MKMarkerAnnotationView {
  override var annotation: MKAnnotation? {
    willSet {
      // 1
      guard let artwork = newValue as? Artwork else {
        return
      }
      canShowCallout = true
      calloutOffset = CGPoint(x: -5, y: 5)
      rightCalloutAccessoryView = UIButton(type: .detailDisclosure)

      // 2
      markerTintColor = artwork.markerTintColor
      if let letter = artwork.discipline?.first {
        glyphText = String(letter)
      }
    }
  }
}

Soon, you’ll register this class as a reusable annotation view for Artwork annotations. The system passes it an annotation as newValue, so here’s what you’re doing:

  1. These lines do the same thing as your mapView(_:viewFor:), configuring the callout.
  2. Then you set the marker’s tint color and also replace its pin icon, or glyph, with the first letter of the annotation’s discipline.

Color My World

Now switch to ViewController.swift, and add this line to viewDidLoad(), before calling loadInitialData():

mapView.register(
  ArtworkMarkerView.self,
  forAnnotationViewWithReuseIdentifier: 
    MKMapViewDefaultAnnotationViewReuseIdentifier)

Here, you register your new class with the map view’s default reuse identifier. For an app with more annotation types, you would register classes with custom identifiers.

Scroll down to the extension and delete mapView(_:viewFor:).

Build and run. Then move the map around to see the different colored and labeled markers:

Map with red, green, blue and purple markers.

In this section of the map, there’s much more art than the map view shows. It reduces clutter by clustering markers that are too close together. In the next section, you’ll see all the annotations.

But first, set the glyph’s image instead of its text. Add the following property to Artwork.swift:

var image: UIImage {
  guard let name = discipline else { 
    return #imageLiteral(resourceName: "Flag") 
  }

  switch name {
  case "Monument":
    return #imageLiteral(resourceName: "Monument")
  case "Sculpture":
    return #imageLiteral(resourceName: "Sculpture")
  case "Plaque":
    return #imageLiteral(resourceName: "Plaque")
  case "Mural":
    return #imageLiteral(resourceName: "Mural")
  default:
    return #imageLiteral(resourceName: "Flag")
  }
}

These images from icons8.com are already in Assets.xcassets.

Then, in ArtworkViews.swift, replace the glyphText lines with:

glyphImage = artwork.image

Build and run to see different colored markers with images:

Map with different colored markers.

And that’s a segue to another customization option and your next task: Replace the markers with images!

Annotations with Images

In ArtworkViews.swift, add the following class:

class ArtworkView: MKAnnotationView {
  override var annotation: MKAnnotation? {
    willSet {
      guard let artwork = newValue as? Artwork else {
        return
      }

      canShowCallout = true
      calloutOffset = CGPoint(x: -5, y: 5)
      rightCalloutAccessoryView = UIButton(type: .detailDisclosure)

      image = artwork.image
    }
  }
}

Now, you’re using a plain old MKAnnotationView instead of an MKMarkerAnnotationView, and the view has an image property.

Back in ViewController.swift, in viewDidLoad(), register this new class, instead of ArtworkMarkerView:

mapView.register(
  ArtworkView.self,
  forAnnotationViewWithReuseIdentifier: 
    MKMapViewDefaultAnnotationViewReuseIdentifier)

Build and run to see all the icons:

Map with many different types and colored markers.

Custom Callout Accessory Views

The right callout accessory is an info button, but tapping it opens Maps. So, now you’ll change the button to show the Maps icon.

Find this line in ArtworkView:

rightCalloutAccessoryView = UIButton(type: .detailDisclosure)

Replace this line with the following code:

let mapsButton = UIButton(frame: CGRect(
  origin: CGPoint.zero, 
  size: CGSize(width: 48, height: 48)))
mapsButton.setBackgroundImage(#imageLiteral(resourceName: "Map"), for: .normal)
rightCalloutAccessoryView = mapsButton

Here, you create a UIButton, set its background image to a map icon, also from icons8.com in Assets.xcassets, then set the view’s right callout accessory to this button.

Build and run. Then tap a view to see the new Maps button:

Map with callout bubble for statue with a Maps button.

The final customization is the detail callout accessory. It’s a single line, which is enough for short location text, but some of the longer location values are truncated like this one:

Map with callout button with a truncated location name.

Now you need a multi-line label. Add the following code to ArtworkView‘s willSet:

let detailLabel = UILabel()
detailLabel.numberOfLines = 0
detailLabel.font = detailLabel.font.withSize(12)
detailLabel.text = artwork.subtitle
detailCalloutAccessoryView = detailLabel

Build and run. Then tap a view to see the long location text in full.

Where To Go From Here?

You can download the completed version of the project using the Download Materials button at the top or bottom of this tutorial.

Now you know the basics of using MapKit, but there’s more you can add: map display customizations, geocoding, geofencing, custom map overlays, and more. Apple’s MapKit documentation and Location and Maps Programming Guide are great places to find more information.

Also look at WWDC 2019 Session 236: What’s New in MapKit and MapKit JS, to find more cool features added in iOS 13.

There’s also have a terrific video course, MapKit and Core Location, that covers many awesome topics.

Core Location Tutorial for iOS: Tracking Visited Locations explains how to track your location and display it using MapKit.

If you have any questions as you use MapKit in your apps, or tips for other MapKit users, please join in the forum discussion below!