MapKit Tutorial: Getting Started

I tweaked some things for Swift 2 - including having to put a ‘?’ after the title and subtitle fields however I now seem to have a problem with types/optionality. any ideas? the line " let placemark = MKPlacemark(coordinate: coordinate, addressDictionary: addressDictionary)" is now coming up with the following error

cannot convert value of type ‘String?’ to expected argument type ‘(String : AnyObject)?’

full code is:

`class Artwork: NSObject, MKAnnotation{
let title: String?
let locationName: String
let discipline: String
let coordinate: CLLocationCoordinate2D

init(title: String, locationName: String, discipline: String, coordinate: CLLocationCoordinate2D) {
    self.title = title
    self.locationName = locationName
    self.discipline = discipline
    self.coordinate = coordinate
    
    super.init()
}

var subtitle: String? {
return locationName
}

// annotation callout info button opens this mapItem in Maps app
func mapItem() -> MKMapItem {
    
    let addressDictionary = subtitle
    let placemark = MKPlacemark(coordinate: coordinate, addressDictionary: addressDictionary)
    
    let mapItem = MKMapItem(placemark: placemark)
    mapItem.name = title
    
    return mapItem
}

}`

you still need a dictionary for the second MKPlacemark argument; also, Contacts has replaced AddressBook, so:

import Contacts instead of import AddressBook

then in mapItem():

let addressDictionary = [CNPostalAddressStreetKey: subtitle!]

Audrey,

For some reason when I added the rest of the pins, they no longer have the detail disclosure info button and I’m not sure where I messed up. The code with the statue still shows it, but when I remove that bit it disappears.

Thank you

hi Michael-did you update the UIButton init to UIButton(type: .DetailDisclosure) as UIView in the MKMapViewDelegate extension?

Yes I did, but it is still not showing up.

the only change I made to the JSON section is in loadInitialData(), replacing // 1 and // 2 with try-catch syntax:

 // 1
 let fileName = NSBundle.mainBundle().pathForResource("PublicArt", ofType: "json");
    var data: NSData?
    do {
      data = try NSData(contentsOfFile: fileName!, options: NSDataReadingOptions(rawValue: 0))
    } catch _ {
      data = nil
    }
    // 2
    var jsonObject: AnyObject? = nil
    if let data = data {
      do {
       jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0))
      } catch _ {
        jsonObject = nil
      }
}

I’m having problems with the second return statement for func mapView. It says you can’t return a nil for MKAnnotationView. Any idea of what I should return?

func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) → MKAnnotationView {

    if let annotation = annotation as? Artwork {
        
        let identifier = "pin"
        var view: MKAnnotationView
        if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) as? MKPinAnnotationView { //2
            dequeuedView.annotation = annotation
            view = dequeuedView
        
        } else {
            //3
            view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
            view.canShowCallout = true
            view.calloutOffset = CGPoint(x: -5, y: 5)
            let button = UIButton(type: UIButtonType.DetailDisclosure)
            view.rightCalloutAccessoryView = button as UIView
        }
       return view
        
    }
   return nil
}

Looks like MKAnnotationView is optional now. Just down to a warning.

Hi I’m having the same problem as Lynn. Not entirely sure what to fix.

Lynn’s second post nailed it: the signature of that method has changed and it now returns an Optional. Accept the warning’s fix, which adds ? to the return type:

func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView?

I changed this:

In Artwork.swift, add this method:

// pinColor for disciplines: Sculpture, Plaque, Mural, Monument, other
func pinColor() → MKPinAnnotationColor {
switch discipline {
case “Sculpture”, “Plaque”:
return .Red
case “Mural”, “Monument”:
return .Purple
default:
return .Green
}
}

To this:

func pinTintColor() → UIColor {
switch discipline {
case “Sculpture”, “Plaque”:
return MKPinAnnotationView.redPinColor()
case “Mural”, “Monument”:
return MKPinAnnotationView.purplePinColor()
default:
return MKPinAnnotationView.greenPinColor()
}

}

But I can’ figure out how to call it in VCMapView.swift
view.pinColor() no longer exists in the MKPinAnnottationView and I don’t see a method for it. What should I be doing?

I tried view.tintColor() = annotation.pinTintColor() but that changes the info button color instead.

Thanks!

view.pinTintColor = annotation.pinTintColor()

:]

It says Value of type MKAnnotationView has no member pinTintColor.

ah, declare the view as MKPinAnnotationView:

func mapView(mapView: MKMapView,
  viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
    if let annotation = annotation as? Artwork {
      let identifier = "pin"
      var view: MKPinAnnotationView
      if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
        as? MKPinAnnotationView { // 2
          dequeuedView.annotation = annotation
          view = dequeuedView
      } else {
        // 3
        view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
        view.canShowCallout = true
        view.calloutOffset = CGPoint(x: -5, y: 5)
        view.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure) as UIView
      }
      
      view.pinTintColor = annotation.pinTintColor()
      
      return view
    }
    return nil
}

Audrey,

i am having issues in loadInitialData function… More scpecific, i would like to know if in the //4 something is changed in swift 2.

`// 3
if let jsonObject = jsonObject as? [String: AnyObject],
// 4
let jsonData = JSONValue.fromObject(jsonObject)?[“data”]?.array {
for artworkJSON in jsonData { …

``

It doesnt recognize the JSONValue type… maybe its just the syntax?

Thanks!

JSONValue is defined in JSON.swift, which is in the HonoluluArtResources.zip file—did you add it to your project?

ah! Thanks, i created from gorund 0 and i forgot!

I’m having a similar problem - if not the same - but I have the JSON.swift file added to the project, installed all cocoa pods and SwiftyJSON into the project, and still have some errors.

    // 3
    if let jsonObject = jsonObject as? [String: AnyObject],
        // 4
        let jsonData = JSONValue.fromObject(jsonObject)?["data"]?.array {
        for artworkJSON in jsonData {
            if let artworkJSON = artworkJSON.array,
                // 5
                **artwork = Artwork.fromJSON(artworkJSON) {**
                artworks.append(artwork)
            }

in the highlighted line I have the error:

Cannot convert value of type ‘[JSONValue]’ to expected argument type ‘JSON’

The JSON file is in the project (copied also), as shown in the figure.

Thanks in advance.

this project doesn’t use cocoa pods or SwiftyJSON ?? maybe revert to a version that doesn’t have this in it?

please check your definition of fromJSON in Artwork.swift; it should start with this:

class func fromJSON(json: [JSONValue]) -> Artwork? {

so the argument is of type [JSONValue] not of type JSON

Thanks! Ok I changed that and fixed that error, I have another one. I changed to SwiftyJSON so I could fix some other errors I had, from stackoverflow, but that is past now.

I followed all the steps from this tutorial but I didn’t want the three tabs on top of the screen. I made a screen with only the map itself, and its functions. I got all working until the options inside the Pin, they don’t appear for me, neither the Maps app, though I have made this option on calloutAcessoryControlTapped, as I show in the figure: