Question

I am trying to use a map to set annotation in it, where the user wants to put it.

I want the user to touch the screen where he wants to put a pin, and by clicking on the appeared pin, he can be redirected to another view where he can put details.

I followed several tutorials to make the button appear on the right of the callout, but this does not work...

Here is my code :

MAPpin is the NSObject file :

MAPpin.h :

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface MAPpin : NSObject <MKAnnotation> {

    CLLocationCoordinate2D coordinate;
    NSString *title;
    NSString *subtitle;
}
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@end

MAPpin.m :

#import "MAPpin.h"

@implementation MAPpin

@synthesize coordinate,title,subtitle, mapView;


@end

And my view controller :

MAPwelcomeViewController.h

#import <UIKit/UIKit.h>
#import <MAPKit/MKAnnotation.h>
#import "MAPAppDelegate.h"
#import "MAPpin.h"

@interface MAPwelcomeViewController : UIViewController <MKMapViewDelegate>
- (IBAction)longpress:(UILongPressGestureRecognizer *)sender;

@property (weak, nonatomic) IBOutlet MKMapView *mapView;

@end

and the MAPwelcomeViewController.m :

#import "MAPwelcomeViewController.h"
#import "MAPpin.h"
#import "myAnnotation.h"
#define METERS_PER_MILE 1609.344

@interface MAPwelcomeViewController ()

@end

@implementation MAPwelcomeViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    {
        [super viewDidLoad];
        _mapView.showsUserLocation = YES;

    }
}
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    //1
    CLLocationCoordinate2D zoomLocation;
    zoomLocation.latitude = 40.740848;
    zoomLocation.longitude= -73.991145;
    // 2
    MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 0.3*METERS_PER_MILE, 0.3*METERS_PER_MILE);
    [self.mapView setRegion:viewRegion animated:YES];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
    [self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];


}
/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/






#pragma mark -MapView Delegate Methods
//6
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    //7
    if([annotation isKindOfClass:[MKUserLocation class]])
        return nil;

    //8
    static NSString *identifier = @"myAnnotation";
    MKPinAnnotationView * annotationView = (MKPinAnnotationView*)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
    if (!annotationView)
    {
        //9
        annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
        annotationView.pinColor = MKPinAnnotationColorPurple;
        annotationView.animatesDrop = YES;
        annotationView.canShowCallout = YES;
    }else {
        annotationView.annotation = annotation;
    }
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    return annotationView;
}

- (IBAction)longpress:(UILongPressGestureRecognizer *)sender {

    CGPoint point = [sender locationInView:self.mapView];

    CLLocationCoordinate2D loccoord = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];


    myAnnotation *ann = [[myAnnotation alloc] initWithCoordinate:loccoord title:@"Test"];
    [self.mapView addAnnotation:ann];

}

@end

So following (http://www.codigator.com/tutorials/mapkit-tutorial-for-ios-beginners/"this links") I added the following method :

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation

But when I run the app, no button is showing... what do you think I am doing wrong ?

Thanks in advance,

regards !

Was it helpful?

Solution

Most likely, the map view's delegate is not set so the viewForAnnotation delegate method never gets called and the map view creates a default red pin with no callout accessory button.

In the storyboard, right-click on the map view control and connect its delegate outlet to the View Controller.

Or, in code, in the viewDidLoad method, before setting showsUserLocation, set the delegate programmatically:

self.mapView.delegate = self;



Some unrelated comments...

Once the button is appearing, to handle the user tapping the callout accessory, a recommended approach is to implement the calloutAccessoryControlTapped delegate method. See the answer to MKAnnotationView Push to View Controller when DetailDesclosure Button is Clicked for an example.

A separate issue I should point out is that the gesture handler method isn't checking the gesture recognizer's state before creating an annotation. So what can happen is multiple pins can get created while the user is still doing a single long press. To avoid this, add a check like this at the top of the longpress: method:

if (sender.state != UIGestureRecognizerStateBegan)
{
    return;
}

Another unrelated thing is that the code is creating an annotation of type myAnnotation by doing myAnnotation alloc but the annotation class you've shown is of type MAPpin.

Finally, adding an MKMapView as an IBOutlet and property in the MAPpin class is completely unnecessary. You should remove it from there before it leads to confusion.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top