1

I looked at the posts for this and I still do not receive a custom pin....

Custom Annotation --> this includes setting my image

 import UIKit
 import MapKit

 class CustomPointAnnotation: MKPointAnnotation {
     var pinCustomImageName: UIImage!
 }

View Controller:

I want to return current location until a button is selected to drop pin

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    //current Location
    if !(annotation is CustomPointAnnotation) {
        return nil
    }
    let reuseIdentifier = "pin"
    var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier)
    if annotationView == nil {
        annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
        annotationView!.canShowCallout = true
        
    } else {
        annotationView!.annotation = annotation
    }
    if let annotationView = annotationView {
        annotationView.image = UIImage(named: "Skyscraper")
        annotationView.canShowCallout = true
    }
   
    return annotationView
}

func addPin() {
    pointAnnotation = CustomPointAnnotation()
    pointAnnotation.pinCustomImageName = UIImage(named: "Skyscraper")
    pointAnnotation.coordinate = currentLocation.coordinate
    pointAnnotation.title = "First Building"
    pointAnnotation.subtitle = "Latitude: \(currentLocation.coordinate.latitude), \ 
     (currentLocation.coordinate.longitude)"
    mapView.addAnnotation(pointAnnotation)
}
Rob
  • 371,891
  • 67
  • 713
  • 902
magellan5
  • 27
  • 5

1 Answers1

0

There's nothing seriously wrong with the code. But there can be a couple of things that would cause problems, including:

  1. Have you set the delegate (either in IB or programmatically) for the map view? If not, your mapView(_:viewFor:) will never be called. Add breakpoint or debugging print statement to confirm.

  2. Have you confirmed that UIImage(named: "Skyscraper") is successfully retrieving an image? Make sure this is not returning nil.


Note, if only iOS 11 and later, you can simplify this code a bit. Since iOS 11, we no longer need for mapView(_:viewFor:) in simple scenarios like this. I would suggest putting the annotation view configuration code within the annotation view subclass, where it belongs, and avoid cluttering our view controller with a viewFor implementation.

So when you do get the current issue behind you, the recommended process is:

  1. Define classes for your annotation and annotation view:

    class CustomAnnotation: MKPointAnnotation {
        var pinCustomImage: UIImage!
    }
    

    And

    class CustomAnnotationView: MKAnnotationView {
        override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
            super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
            canShowCallout = true
            update(for: annotation)
        }
    
        override var annotation: MKAnnotation? { didSet { update(for: annotation) } }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        private func update(for annotation: MKAnnotation?) {
            image = (annotation as? CustomAnnotation)?.pinCustomImage
        }
    }
    
  2. In viewDidLoad register this annotation view class:

    mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
    
  3. Remove mapView(_:viewFor:) implementation.

Now when you add a CustomAnnotation to your map’s list of annotations, it will be rendered correctly.

But I would suggest resolving your current problem first. There’s no point in refining you implementation until these more basic issues are resolved.

Rob
  • 371,891
  • 67
  • 713
  • 902
  • This works perfectly thank you. Do you know how to add custom animation to the pin such as it bounces up and down upon addition? As well as how do you save this pin for future use using user.defaults? – magellan5 Oct 21 '20 at 01:30
  • Re animation with bouncing, you have to do that yourself. E.g. you could [add animation](https://gist.github.com/robertmryan/b01eba51f2eabab05a01315b71b2548e) to the `CustomAnnotationView`. Or you could [implement this](https://stackoverflow.com/questions/6808876/how-do-i-animate-mkannotationview-drop) in your `MKMapViewDelegate`, too (though that, conceptually, seems like the wrong place to do it, IMHO). – Rob Oct 21 '20 at 15:24
  • Re saving pin in persistent storage, [make your annotation conform](https://gist.github.com/robertmryan/c7e025f1b795735a86fb6f29743631df) to `Codable` and then you can encode an array of annotations into JSON or a plist which you can then write to and read from persistent storage (e.g. the app support directory). (UserDefaults is not the right place for application storage.) But if you do that, you probably want to only store the image name in the annotation, not the whole image, as I've shown in that example. – Rob Oct 21 '20 at 15:27