Creating the RestaurantItem class

To represent restaurant locations on the Map screen, you will create a class, RestaurantItem, that conforms to MKAnnotation. When RestaurantItem objects are added to a map view, the delegate object (usually a view controller) of the map view will automatically provide MKAnnotationView, which appears as a pin, on the map view.

You need the location of the restaurant so that you can set the coordinate property of the RestaurantItem instance. The restaurant location data will be provided as a .plist file. Before you create the RestaurantItem class, you need to import the .plist file containing the restaurant details into your app. Do the following steps:

  1. Open the LetsEat project. In the Project navigator, right-click the LetsEat folder and create a new group called Map.
  2. Right-click the Map folder and create a new group called Model.
  3. If you have not yet done so, download the completed project and project resources from https://github.com/PacktPublishing/iOS-13-Programming-for-Beginners and find the Maplocations.plist file inside the resources folder in the Chapter16 folder.
  4. Drag the Maplocations.plist file to the Model folder in your project, and click it to view its contents. You'll see that it is an array of dictionaries, with each dictionary representing a restaurant's details (including its location). You'll need to create properties for the data that you will use, which will be assigned to RestaurantItem and eventually be displayed on the Restaurant Detail screen:

Next, you'll create the RestaurantItem class. Perform the following steps:

  1. Right-click the Model folder and select New File.
  2. iOS should already be selected. Choose Cocoa Touch Class and then click Next.
  3. Configure the file as follows:
  • Class: RestaurantItem
  • Subclass: NSObject
  • Also create XIB: Greyed out
  • Language: Swift
  • Click Next
  1. Click Create. RestaurantItem.swift appears in the Project navigator.
  2. In RestaurantItem.swift, under import UIKit, add import MapKit. This tells Xcode you will be using the MapKit framework and gives you access to protocols such as MKAnnotation and MKMapViewDelegate.
  3. Modify the class declaration as follows:
import UIKit
import MapKit

class RestaurantItem: NSObject, MKAnnotation {

}

This means RestaurantItem conforms to MKAnnotation. You'll see an error. This is because you have not yet implemented the coordinate property, which is a required property to conform to MKAnnotation. You will do so shortly.

  1. Type the following inside the curly braces:
var name: String?
var cuisines:[String] = []
var lat: Double?
var long: Double?
var address: String?
var postalCode: String?
var state: String?
var imageURL: String?

These are the properties that will hold the data you get from Maplocations.plist. Note that you haven't created properties to store every detail of a restaurant stored in Maplocations.plist, and that's fine. You only need to create properties for the details relevant to the app.

  1. You'll use a custom initializer to get the data from the .plist file into instances of RestaurantItem. Type the following after the last property declaration:
init(dict:[String:AnyObject]){
if let lat = dict["lat"] as? Double { self.lat = lat }
if let long = dict["long"] as? Double { self.long = long }
if let name = dict["name"] as? String { self.name = name }
if let cuisines = dict["cuisines"] as? [String]
{ self.cuisines = cuisines }
if let address = dict["address"] as? String
{ self.address = address }
if let postalCode = dict["postalCode"] as? String
{ self.postalCode = postalCode }
if let state = dict["state"] as? String
{ self.state = state }
if let image = dict["image_url"] as? String
{ self.imageURL = image }
}

Even though this initializer looks complicated, it's actually quite straightforward. Each line looks for a specific dictionary item key and assigns its value to the corresponding property. For example, the first line looks for the dictionary item with a key containing lat and assigns the associated value to the lat property. Note the lat and long properties, which will be used to create the value for the coordinate property.

  1. Type the following after the init(dict:) method to implement the coordinate property:
var coordinate: CLLocationCoordinate2D {
guard let lat = lat, let long = long else
{ return CLLocationCoordinate2D() }
return CLLocationCoordinate2D(latitude: lat, longitude: long)
}

The coordinate property is a required property for the MKAnnotation protocol. It is of the CLLocationCoordinate2D type, and it holds a geographical location.

Note that the coordinate property's value is not assigned directly, but is derived from the lat and long properties. The guard statement gets the latitude and longitude values from the lat and long properties, which are then used to create the value for the coordinate property. Such properties are called computed properties.

  1. Add the following above the coordinate property to implement the subtitle property:
var subtitle: String? {
if cuisines.isEmpty { return "" }
else if cuisines.count == 1 { return cuisines.first }
else { return cuisines.joined(separator: ", ") }
}

subtitle is also a computed property. The first line checks to see whether the cuisines property is empty, and if so, returns an empty string. If the cuisines property contains a single item, that item will be returned. If the cuisines property has more than a single item, each item is added to a string, with a comma in between items. For example, if cuisines contained the ["American", "Bistro", "Burgers"] array, the generated string would be American, Bistro, Burgers.

  1. Finally, implement the title property by adding the following above the subtitle property:
var title: String? {
return name
}

This just returns the contents of the name property.

Your RestaurantItem class is now complete and free of errors and should look as follows:

import UIKit
import MapKit

class RestaurantItem: NSObject, MKAnnotation {
var name: String?
var cuisines:[String] = []
var lat: Double?
var long: Double?
var address: String?
var postalCode: String?
var state: String?
var imageURL: String?

init(dict:[String:AnyObject]){
if let lat = dict["lat"] as? Double { self.lat = lat }
if let long = dict["long"] as? Double { self.long = long }
if let name = dict["name"] as? String { self.name = name }
if let cuisines = dict["cuisines"] as? [String]
{ self.cuisines = cuisines }
if let address = dict["address"] as? String
{ self.address = address }
if let postalCode = dict["postalCode"] as? String
{ self.postalCode = postalCode }
if let state = dict["state"] as? String { self.state = state }
if let image = dict["image_url"] as? String { self.imageURL = image }
}

var title: String? {
return name
}

var subtitle: String? {
if cuisines.isEmpty { return "" }
else if cuisines.count == 1 { return cuisines.first }
else { return cuisines.joined(separator: ", ") }
}

var coordinate: CLLocationCoordinate2D {
guard let lat = lat, let long = long else {
return CLLocationCoordinate2D() }
return CLLocationCoordinate2D(latitude: lat, longitude: long)
}
}

You have added Maplocations.plist to your app, and you have created the RestaurantItem class. Next, let's create a data manager class that reads restaurant data from Maplocations.plist and puts it into RestaurantItem instances, so they can be used by your app.

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

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