1

I wonder how to set different images to annotation pins on mapview. The difference between the following questions

viewForAnnotation confusion and customizing the pinColor iteratively

Swift different images for Annotation

is that my array of images is generated dynamically with regard to server response. There is no fixed size of the array, so switch/case construction is not a good idea. Moreover, I'm not sure how to apply the solution with custom class aforementioned in topic above. I'm aware that it would be better to post a comment to one of the questions asked before, but unfortunately I'm too rookie at the moment to do that(too few points).

This is the for loop performed inside functions that shows map:

for var r=0;r<arrayOfRestaurants.count;r++
    {

        var summonRestaurant:NSDictionary = arrayOfRestaurants[r] as NSDictionary
        var nearbyRestaurant = Restaurant(nearbyRestaurants:summonRestaurant)
        var latRestaurant=(nearbyRestaurant.latitude as NSString).doubleValue
        var longRestaurant=(nearbyRestaurant.longitude as NSString).doubleValue
        var locationOfRestaurant = CLLocationCoordinate2D(
            latitude: latRestaurant as CLLocationDegrees, longitude: longRestaurant as CLLocationDegrees)
        var lunchArray: NSArray = nearbyRestaurant.lunch as NSArray
        var annotation = MKPointAnnotation()

        annotation.setCoordinate(locationOfRestaurant)
        annotation.title = nearbyRestaurant.name + "  " + nearbyRestaurant.distance + " km"
        map.addAnnotation(annotation)
}

And here is viewForAnnotation delegate method(quite identical to the method used in aforementioned threads):

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

        if annotation is MKUserLocation {
            //return nil so map view draws "blue dot" for standard user location
            return nil
        }

        let reuseId = "pin"

        var pinView = map.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
        if pinView == nil {
            pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
            pinView!.canShowCallout = true
            pinView!.animatesDrop = true
            pinView!.pinColor = .Purple

            pinView!.image = globalImageArray[0]

            }
        else {
            pinView!.annotation = annotation
        }

        return pinView
}

As you can see, I assigned a certain image to pinView which is globalImageArray[0], but I look for a solution that let me iterate over the globalImageArray and assign a certain image to each pin.

I'd be glad to receive any help, thanks in advance!

Community
  • 1
  • 1
theDC
  • 6,364
  • 10
  • 56
  • 98
  • What is the relationship between an annotation and a pin? How do you know which image goes with each annotation? – Paulw11 Jan 19 '15 at 20:51
  • images in array go in the same sequence as pins are created, each item of arrayOfRestaurants has a corresponding item in globalImageArray – theDC Jan 19 '15 at 20:54
  • So rather than using an MKPointAnnotation you need to create your own class that adopts the MKAnnotation protocol and store the image in a property of he annotation itself. This is basically the approach in the second question you linked – Paulw11 Jan 19 '15 at 20:57
  • I'm afraid I'm not sure how to do it well. Would you mind elaboration through answering the question? thanks! – theDC Jan 19 '15 at 21:02

1 Answers1

4

First, you need to create your own class that adopts the MKAnnotation protocol for your annotations -

class RestaurantAnnotation : NSObject, MKAnnotation {
    var coordinate: CLLocationCoordinate2D
    var title: String
    var subtitle: String
    var image: UIImage?

    init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String) {
        self.coordinate = coordinate
        self.title = title
        self.subtitle = subtitle
    }
}

Then, use instances of this class when you add the annotation and set the image -

for var r=0;r<arrayOfRestaurants.count;r++
    {

        var summonRestaurant:NSDictionary = arrayOfRestaurants[r] as NSDictionary
        var nearbyRestaurant = Restaurant(nearbyRestaurants:summonRestaurant)
        var latRestaurant=(nearbyRestaurant.latitude as NSString).doubleValue
        var longRestaurant=(nearbyRestaurant.longitude as NSString).doubleValue
        let locationOfRestaurant = CLLocationCoordinate2D(
            latitude: latRestaurant as CLLocationDegrees, longitude: longRestaurant as CLLocationDegrees)
        var lunchArray: NSArray = nearbyRestaurant.lunch as NSArray

        let title = nearbyRestaurant.name + "  " + nearbyRestaurant.distance +" km"
        var annotation = RestaurantAnnotation(coordinate, title:title, subtitle:"")
        annotation.image = globalImageArray[r]
        map.addAnnotation(annotation)
}

Now, in your view for annotation you can access the image -

func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
    if !(annotation is RestaurantAnnotation) {
        return nil
    }

    let reuseId = "restaurant"
    var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
    if anView == nil {
        anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
        anView.canShowCallout = true
    }
    else {
        anView.annotation = annotation
    }

    let restaurantAnnotation = annotation as RestaurantAnnotation

    if (restaurantAnnotation.image != nil) {
            anView.image = restaurantAnnotation.image!
            anView.image.layer.setCornerRadius(8.0)
            anView.image.layer.clipsToBounds=true
        }
        else {
         // Perhaps set some default image
        }

    return anView
}
Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • 1
    Thank you man, this is outstanding, works perfectly fine! I'm so thankful! I slightly modified the line with creating a custom class into var annotation = RestaurantAnnotation(coordinate: locationOfRestaurant, title: "somestring", subtitle: "somestring") so it's ok with the defined initializer. Nonethless, thank you! – theDC Jan 19 '15 at 21:52
  • Great. I don't really use Swift, so I wasn't sure whether the default initialiser would work as well. – Paulw11 Jan 19 '15 at 21:55
  • One more short question if you don't mind : I want to set that pins images with rounded corners, should it be done in annotation class or directly inside delegate method? Because there's some problem with UIImage vs UImageView – theDC Jan 19 '15 at 22:22
  • See my edits. You could probably set the rounded corners when you load the image into the array as an alternative to setting it in the annotation view function – Paulw11 Jan 19 '15 at 23:04
  • I tried something similar, but it didn't work, the app crashed. But I guess the reason was that I resized the image just before doing that. Thanks bro for your effort, I will try to figure it out by myself and if I fail, I'll post a relevant question. – theDC Jan 19 '15 at 23:16
  • Hi, Paulw11 i followed your example and it worked great. I had to modify a few lines of code to fit my needs, but work great nonetheless – TheRealRonDez Jan 26 '15 at 15:54