Displaying data in the static table view

You have successfully connected all the outlets in RestaurantDetailViewController to the user interface elements in the table view for the Restaurant Detail screen. Since this is a static table view, you won't be using the methods that have been declared in the UITableViewDataSource protocol to populate the outlets. Instead, you will write custom methods to do so. Do the following steps:

  1. Click RestaurantDetailViewController.swift in the Project navigator.
  2. Add the following code after the existing import statement:
import MapKit

This is required since you will be using MapKit's properties and methods to generate an image of a map for the image view in the last cell.

  1. Add the following code after the last curly brace:
private extension RestaurantDetailViewController {

func setupLabels() {
guard let restaurant = selectedRestaurant else { return }
if let name = restaurant.name {
lblName.text = name
title = name
}
if let cuisine = restaurant.subtitle {
lblCuisine.text = cuisine
}
if let address = restaurant.address {
lblAddress.text = address
lblHeaderAddress.text = address
}
lblTableDetails.text = "Table for 7, tonight at 10:00 PM"
}
}

As before, you will use a private extension to organize your code. The setupLabels() method is quite straightforward; it gets values from a RestaurantItem instance and puts them into the outlets in RestaurantDetailViewController, with the exception of lblTableDetails, which is just assigned a string.

In the last cell, you will display a map. It is possible to display an actual map view in the last cell, but that would take up a lot of system resources. What you will do instead is generate an image from a map region and set the imgMap outlet to display that image. This image will also display the same custom annotation image you used in the Map screen.

  1. Add the following method under setupLabels() and before the last curly brace:
func createMap() {
guard let annotation = selectedRestaurant,
let long = annotation.long,
let lat = annotation.lat else { return }
let location = CLLocationCoordinate2D(latitude: lat, longitude: long)
takeSnapShot(with: location)
}

This method assigns selectedRestaurant to annotation and creates location using the lat and long properties of selectedRestaurant. Then, it calls takeSnapShot(with:), passing location as a parameter.

  1. You'll see an error since takeSnapShot(with:) hasn't been implemented yet, so add the following code after the createMap() function:
func takeSnapShot(with location: CLLocationCoordinate2D){

let mapSnapshotOptions = MKMapSnapshotter.Options()
var loc = location
let polyline = MKPolyline(coordinates: &loc, count: 1 )
let region = MKCoordinateRegion(polyline.boundingMapRect)

mapSnapshotOptions.region = region
mapSnapshotOptions.scale = UIScreen.main.scale
mapSnapshotOptions.size = CGSize(width: 340, height: 208)
mapSnapshotOptions.showsBuildings = true
mapSnapshotOptions.pointOfInterestFilter = .includingAll

let snapShotter = MKMapSnapshotter(options: mapSnapshotOptions)
snapShotter.start() { snapshot, error in guard
let snapshot = snapshot else { return }
UIGraphicsBeginImageContextWithOptions(mapSnapshotOptions.size,
true, 0)
snapshot.image.draw(at: .zero)

let identifier = "custompin"
let annotation = MKPointAnnotation()
annotation.coordinate = location

let pinView = MKPinAnnotationView(annotation: annotation,
reuseIdentifier: identifier)
pinView.image = UIImage(named: "custom-annotation")!
let pinImage = pinView.image
var point = snapshot.point(for:location)

let rect = self.imgMap.bounds
if rect.contains(point) {
let pinCenterOffset = pinView.centerOffset
point.x -= pinView.bounds.size.width/2
point.y -= pinView.bounds.size.height/2
point.x += pinCenterOffset.x
point.y += pinCenterOffset.y
pinImage?.draw(at: point)
}
if let image = UIGraphicsGetImageFromCurrentImageContext() {
UIGraphicsEndImageContext()
DispatchQueue.main.async {
self.imgMap.image = image
}
}
}
}

A full description of this method is beyond the scope of this book, but let's go over a simple explanation of what it does. Given a location, it takes a snapshot of the map at that location, adds the custom annotation you used earlier in the Map screen, converts it into an image, and assigns it to the imgMap outlet in RestaurantDetailViewController.

You have written all the methods that are required for RestaurantDetailViewController to display the desired RestaurantItem details in the Restaurant Detail screen. Now, you need to call them, as follows:

  1. In the private extension, add the following method, just above setupLabels():
func initialize() {
setupLabels()
createMap()
}

This method calls setupLabels() and createMap().

  1. The initialize() method needs to be called inside viewDidLoad() so that it will be executed when RestaurantDetailViewController loads its view. Modify viewDidLoad(), as follows:
override func viewDidLoad() {
super.viewDidLoad()
initialize()
}

Now, you have finished with RestaurantDetailViewController, but you still need to pass the selected RestaurantItem instance from RestaurantListViewController to RestaurantDetailViewController. You will write the code to do this in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.178.157