Search code examples
iosmapscoordinatestapdisclosure

Getting coordinates from pin's annotation's disclosure, on tap


i'll try to keep this very simple :

I'm very new to Objective-C (or programming actually) so i'll probably need an explanation more than just an answer.

What i'm trying to do and can't do (yet): Getting a pin's coordinate after tapping it's disclosure, and eventually pass it through a segue. Practically, i'm clicking my "info" icon on a pin I just created, and i'd like to see it's info in another page (a webview). This page would show coordinates (and other stuff that we don't need here).

Why : Practically, i'm clicking my "info" icon on a pin's annotation created earlier by the user, and i'd like to see it's info in another page (a webview). This page would show coordinates (and other stuff that we don't need here).

My pins coordinates are stored into a

CLLocationCoordinate2D location;

I can't re-use the variables i used before because they might be outdated (it would only work if the user asks for the last one created...) And I do not know how i can get a pin's coordinates ; there must be a method or something but i jsut can't find it. I've found MANY answers on the internet, and none seemed to work, probably because i didn't understand them properly. Anyway, i couldn't use them.

I'll show you bits of my code, it's pretty straight forward i guess :

There is the viewDidLoad, you probably want to see it, i guess :

- (void)viewDidLoad
{
    [super viewDidLoad];
    name = [[NSString alloc]init];
    detail = [[NSString alloc]init];
    UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longpressToGetLocation:)];
    lpgr.minimumPressDuration = 2.0;  //user must press for 2 seconds
    [_map addGestureRecognizer:lpgr];
    CLLocationCoordinate2D loc = CLLocationCoordinate2DMake(50.837863, 4.353616);
    MKCoordinateSpan span = MKCoordinateSpanMake(.035, .035);
    MKCoordinateRegion reg = MKCoordinateRegionMake(loc, span);
    self.map.region = reg;
    [self buildBaseAnno];
    self.map.showsUserLocation = true;
}

I know this is important but to be honest i don't fully understand how this bit works ; still, it does work. :D

    -(MKAnnotationView*)mapView:(MKMapView*)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    MKAnnotationView* v = nil;
    {
        static NSString* ident = @"Pin";
        v = [_map dequeueReusableAnnotationViewWithIdentifier:ident];
        if (v == nil)
        {
            v = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ident];
            ((MKPinAnnotationView*)v).pinColor = MKPinAnnotationColorRed;
            UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
            v.rightCalloutAccessoryView = infoButton;
            v.centerOffset= CGPointMake(0,-20);
            v.canShowCallout= YES;
        }
        v.annotation = annotation;
    }
    return v;
}

Touch pin creation :

- (void)longpressToGetLocation:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer.state != UIGestureRecognizerStateBegan)
        return;

    CGPoint touchPoint = [gestureRecognizer locationInView:self.map];
    location = [self.map convertPoint:touchPoint toCoordinateFromView:self.map];

    [self showAlertName];
}

The actual annotation/pin creation method

-(void)buildAnno
{
    CLLocationCoordinate2D coordinate;
    coordinate.latitude = location.latitude;
    coordinate.longitude = location.longitude;
    MKPointAnnotation* newann = [MKPointAnnotation new];
    newann.coordinate = coordinate;

    newann.title = name;
    newann.subtitle = detail;
    [self.map addAnnotation:newann];
}

Please, do tell if you need more of the code ; i'm not really sure what i can give you, as my code is probably 'correct' (or decent), i just need to actually know how to get the information i need (that is, coordinates and other stuff from the pin i just tapped.)

And i actually don't tap the pin, i tap the disclosure in the pin's annotation. Anyway, That's enough for now !

Once i can catch these coordinates, i believe i'll be able to pass them through the segue as passing Data is already well explained here, but if there is anything 'special', i'd be really glad if you could add it to your explanation because i'm still really uncomfortable with all this and most of the tutorials/guides/links i've found didn't really help me.

Thank you very much for your time and help :)

(Edit : I had found a similar question here but i believe i need extra help/explanation.)


Solution

  • You don't need the gesture recogniser - the map view delegate protocol already has a method that tells you when the callout accessory was tapped calloutAccessoryControlTapped and this method receives the relevant annotationView. The annotationView.annotation property gets you back to the relevant annotation object and then you can access its coordinate property to get the coordinates of the pin.

    First, create a new property in your class:

     @property CLLocationCoordinate2D tappedCoord;
    

    then implement the delegate method

    - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
    {
        MKPointAnnotation *annotation=(MKPointAnnotation*)view.annotation;
        self.tappedcoord=annotation.coordinate;
        [self performSegueWithIdentifier:@"detailViewSegue"];   // Use your appropriate segue identifier
    }
    

    Then you can access the property in prepareForSegue (again, change to the appropriate segue name and destination view controller class)

    -(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
        if ([segue.identifier isEqualToString:@"detailViewSegue" ]){
            DetailViewController *dvc=(DetailViewController *)segue.destinationViewController;
            dvc.coord=self.tappedCoord;
    }
    

    Also, since your MapView is displaying the user's location, there will be an annotation for that. You need to address this in your viewForAnnotation method, returning nil if the annotation isn't one of yours. You can check the class of the annotation to determine this -

    -(MKAnnotationView*)mapView:(MKMapView*)mapView viewForAnnotation:(id <MKAnnotation>)annotation
    {
        MKAnnotationView* v = nil;
        if ([annotation isMemberOfClass:[MKPointAnnotation class]]) {
            static NSString* ident = @"Pin";
            v = [_map dequeueReusableAnnotationViewWithIdentifier:ident];
            if (v == nil)
            {
                v = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ident];
                ((MKPinAnnotationView*)v).pinColor = MKPinAnnotationColorRed;
                UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
                v.rightCalloutAccessoryView = infoButton;
                v.centerOffset= CGPointMake(0,-20);
                v.canShowCallout= YES;
            }
            v.annotation = annotation;
        }
        return v;
    }