Assignment 5

Where in the World

Due Dates

Resources

Create Your Repository

Assignment

In this assignment, you will create a map based application that will highlight Chicago landmarks.

The application will make use of MapKit for displaying points of interest on the map and many Foundation classes for managing the data associated with each location. This application will make use of adaptive layout techniques so that it will adjust to the users screen size and orientation.

This assignment will require the use of both Storyboards and programmatic interface design.

Project Setup

If you use the Xcode template, this should happen almost automatically. The default behavior provides the adaptive layout that we want. You may just need to check the contraints on your views to provide different values between Regular and Compact size classes.

Figure 1. The application’s main screen in portrait mode.

Map View Controller

The MapViewController should display a full screen MapView. Set the map views properties so that it does not show any points of intersest (as we will be using our own). Also, disable the compass so that it doesn’t over crowd our interface.

mapView.showsCompass = false
mapView.pointOfInterestFilter = .excludingAll

The map’s initial region should be focused on the City of Chicago. Use a variant of MKCoordinateRegion() method to accomplish this.

Add a partially transparent UIView that will highlight details of a point of interest in our map. The view should contain two UILabels, one for the title and one for a description. Add a UIButton to the view that is styled with a star to represent if a places is a favorite. Make sure to add a differently styled star for the selected state of the button. This can be accomplished in Storyboards or programmatically.

Tip: Use a SFSybmol star and star.fill for the button image.

Position a large UIButton at the bottom of the screen. The button’s title should be “Favorites”. The button should be on-top of the map (remember the map should be full screen). Color the button so that it is visually distinct.

The overall layout should look similiar to Figure 1 (portrait orientation) and Figure 3 (landscape orientation.)

Map Annotations

Annotate the map with annotations representing points of interest in Chicago. Use the information in Data.plist for your annoation. You may add additional annotations if you would like.

Create a custom annotation, Place by subclassing MKPointAnnotation:

class Place: MKPointAnnotation {
    // Name of the point of interest
      var name: String?
    // Description of the point of interest
      var longDescription: String?
  
}

You may add additional properties as needed.

Create a custom annotation view, PlaceMarkerView by subclassing MKMarkerAnnotations. You can style the markers as you like, this example is just a reference.

class PlaceMarkerView: MKMarkerAnnotationView {
  override var annotation: MKAnnotation? {
      willSet {
        clusteringIdentifier = "Place"
        displayPriority = .defaultLow 
        markerTintColor = .systemRed
        glyphImage = UIImage(systemName: "pin.fill")
        }
  }
}

Implement the func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) method so that when an annotation is tapped, the title and description of the annotation appears in the display view.

Tip: Don’t forget to implement MKMapViewDelegate and set the delegate property as the map view controller.

Favorites View Controller

Tapping on the “Favorites” button in the map view controller should present the FavoritesViewController modally. You may present the view controller using a segue or programmatically.

The FavoritesViewController should contain a UITableView that will display a list of the user’s favorite places. You may use a default cell style or a custom cell. When a user taps on a cell the following should happen:

  1. The FavoritesViewController should send the information about the tapped cell to the MapViewController using a custom protocol and delegate.
  2. The FavoritesViewController should dismiss.
  3. When the MapViewController appears, the map’s region should change to highlight the favorite place.
  4. The map view’s display view should should the information for the selected favorite place.

Place a UIButton on the top of the view controller that allows the user to dismiss the view controller. When the view is dimissed in this manner, nothing should happen.

Figure 2. The favorites view controller.

The overall layout should look similiar to Figure 2 (portrait orientation) and Figure 4 (landscape orientation.)

Data Model

Create a data manager singleton, name DataManager to handle all the data processing and storage. Follow the recommended singleton pattern below:

public class DataManager {
  
  // MARK: - Singleton Stuff
  public static let sharedInstance = DataManager()
  
  //This prevents others from using the default '()' initializer
  fileprivate init() {}

  // Your code (these are just example functions, implement what you need)
  func loadAnnotationFromPlist() {}
  func saveFavorites() {}
  func deleteFavorite() {}
  func listFavorites() {}
  ...
}

Within this class, implement functions to allow you to save, delete and list the users’ favorites. Tapping on the star on the MapViewController should toggle it as a “favorite”. When a place is a “favorite”, the star should be filled. Use UserDefaults for persistant storage.

Custom Protocol

Implement a custom protocol that will allow your FavortiesViewController to pass messages back to the MapViewController.

Here is an example, but you may customize to fit your data model.

protocol PlacesFavoritesDelegate: class {
  func favoritePlace(name: String) -> Void
}

Ensure that the MapViewController conforms to this protocol. Also, make sure that FavoritesViewController has a delegate property that conforms to the protocol.

weak var delegate: PlacesFavoritesDelegate?

This provides the connection between the objects that will allow them to communicate.

Note that declaring you delegate property as weak prevents a retain cycle where two objects (MapViewController and FavoritesViewController) have a strong reference to the object and it will never allows it be released from memory (ie. a leak).

In MapViewController, implement the protocol method to center the map region on the favorite place and update the display view’s labels.

extension MapViewController: PlacesFavoritesDelegate {
  func favoritePlace(name: String) {
   // Update the map view based on the favorite
   // place that was passed in
  }
}

Adaptive Layout

Use adaptive layout techniques to ensure that your app takes advantage of different screen orientations.

Figure 2. The application’s main screen in landscape mode.

In the MapViewController, make the display view larger and justified on the left side of the schree. Also, decrease the height to the “Favorites” button.

Figure 4. The favorites view controller in landscape.

In the FavoritesViewController ensure that the table and header view are full screen. The dismiss button should remain fixed on the top of the view controller.

Extra Credit (10%)

Add local notifications that use a location based trigger to inform the user when they are near a point of interest. This will require you to simulata locations in Xcode to properly test this feature. See this tutorial for more infomation (https://blackpixel.com/writing/2016/05/simulating-locations-with-xcode-revisited.html).

App Icon

Grading