2
votes

I am developing an app using swift and mapkit. The mapView has some annotations in addition to the mainUser annotation view. What I want is when the user selects a cell in a UITableViewCell from another ViewController, he should be brought to the mapView ViewController and a specific pin to be selected. I do this by passing an object called "fromSegue". All of this works great, except when the user wants to select itself: Selecting any kind of CustomPointAnnotationView is no problem, but when it comes to selecting the userLocation, the function ViewForAnnotation is not called yet.

Here is the function that sets the region of the map. This is where the annotation selection is supposed to occur.

    func setFPS() {
    print("[SFPS] - setFPS")
    self.mainUser.setObject(mainUserLocation.latitude, forKey: "latitude")
    self.mainUser.setObject(mainUserLocation.longitude, forKey: "longitude")
    if self.fromSegue != nil {
        print("[SFPS] - setModFPS")
        if fromSegue.type == 11 {
            print("[SFPS] - type11 - Showing a notif of type 11")
            let latititi:Double = fromSegue.latitude as! Double
            let longigigi:Double = fromSegue.longitude as! Double
            self.mapScope = CLLocationCoordinate2DMake(latititi, longigigi)
            var annotJar = pinJar.filter{$0.nickName == self.fromSegue.name}
            print("[SFPS] - type11 - ALL RIGHT LETS DO IT")
            let annot = annotJar[0]
            Map.selectAnnotation(annot,animated: true)
            fromSegue = nil
            print("[SFPS] - type11 - Over")
        } else if fromSegue.type == 21 {
            print("[SFPS] - type21 - Showing a notif of type 21")
            Map.selectAnnotation(self.Map.userLocation,animated: true)
            self.mapScope = mainUserLocation
            fromSegue = nil
        } else {
            print("[SFPS] - no type! problem here")
            self.mapScope = CLLocationCoordinate2DMake(mainUserLocation.latitude, mainUserLocation.longitude)
        }
    } else {
        self.mapScope = CLLocationCoordinate2DMake(mainUserLocation.latitude, mainUserLocation.longitude)
    }
    Map.rotateEnabled = true
    let span = MKCoordinateSpanMake(0.001, 0.001)
    print("[SFPS] - span made")
    let region = MKCoordinateRegionMake(mapScope, span)
    print("[SFPS] - region made")
    Map.setRegion(region, animated: true)
    print("[SFPS] - region is all set - Over")
}

When fromSegue is of type 11, it should select a customPointAnnotationview. And this is what happens in the console:

[SFPS] - setFPS
[SFPS] - setModFPS
[SFPS] - type11 - Showing a notif of type 11
[SFPS] - type11 - ALL RIGHT LETS DO IT
[VFA] - ViewForAnnotation
[VFA] - the annotation: <PING.CustomPointAnnotation: 0x1890d570>.  from: Optional(Optional("newParse44"))
[VFA] - of kind random folk
[VFA] - of kind random folk - building...
[DSAV] - didSelectAnnotationView: Optional(Optional("newParse44"))
[DSAV] - guest
[DSAV] - Optional("newParse44") selected
[SFPS] - type11 - Over
[SFPS] - span made
[SFPS] - region made
[SFPS] - region is all set - Over

The function setFPS() is being executed, right when the annotation is about to be selected, it is created, then selected, then the rest of setFPS() is executed. Great! Everything works here.

Now when fromSegue is of type 21, the userLocation pin should be selected. And here is what happens in the console:

[SFPS] - setFPS
[SFPS] - setModFPS
[SFPS] - type21 - Showing a notif of type 21
2015-11-06 07:40:31.116 PING[1272:574013] ERROR: Trying to select an annotation which has not been added
[SFPS] - span made
[SFPS] - region made
[SFPS] - region is all set - Over

So in this case the userlocation annotation has not been added because viewForAnnotation has not been called (early enough?). My question is why? Could I call viewForAnnotation manually?

Thank you very much for your help

3

3 Answers

1
votes

Try setCenterCoordinate before selectAnnotation on MKMapView

For example:

mapview.setCenterCoordinate(mapview.userLocation.coordinate, animated: false)
mapview.selectAnnotation(mapview.userLocation,animated: true)

Update:
It needs some time to get the user location.
MKMapViewDelegate has didUpdateUserLocation which updates on every location update. We want to get the userLocation when it fires for the first time then select it.

Make a bool var in the ViewController. This var will be used to select the annotation for the first time. We want to ignore all other callbacks of didUpdateUserLocation.

class MapViewController: UIViewController {    
    var didUpdateUserLocation = false
    ...
    ...
}

Now implement the MKMapViewDelegate's didUpdateUserLocation function.

extension MapViewController : MKMapViewDelegate {

    func mapView(mapView: MKMapView, didUpdateUserLocation userLocation: MKUserLocation) {

        if !didUpdateUserLocation {
            mapView.selectAnnotation(mapView.userLocation, animated: true)
            didUpdateUserLocation = true
        }
    }
}
0
votes

if you want to call ViewForAnnotation when you select itself, you must add an annotation on itself’s location. When you click on the system annotation, it won’t call the method ViewForAnnotation

0
votes

Thanks to @Warif hints, I came up with this solution. While I am aware this is a terrible goldberg machine, it gets the work done.

Setting up a bool in didupdatelocations did not work because I had to wait for the viewforannotation to be called. I tried to put the bool when the viewforannotation was called for the mainuserlocation but it didn't work either (weird bug about the user image). I finally decided to setup an Int acting as a count to know when all previous steps are done and I can select the annotation.

class MapViewController: UIViewController {   
    var didUpdateUserLocation: Int = 0
    ...
    ...
    }

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if self.fromSegue != nil {
        if self.fromSegue.type == 21 {
            if self.didUpdateUserLocation == 0 {
                self.didUpdateUserLocation = 1
            }
        }
    }
}

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
       if self.fromSegue != nil {
           if self.fromSegue.type == 21 {
               if self.didUpdateUserLocation == 1 {
                   self.didUpdateUserLocation = 2
               }
           }
       }
    ...
    ...
    ...
    }


override func viewDidAppear(animated: Bool) {
    if self.fromSegue != nil {
       if self.fromSegue.type == 21 {
           if self.didUpdateUserLocation == 2 {
               Map.selectAnnotation(self.Map.userLocation,animated: true)
               self.fromSegue = nil
               self.didUpdateUserLocation = 3
           }
        }
    }
}