I have written simple mapView application.It is showing two kind of problems.
1- Execution is stopping on Thread 1: signal SIGABRT error.
2- This function is showing compile time error .
- (IBAction)findMe:(id)sender {
If( [[toggleButton titleForState:UIControlStateNormal] isEqualToString:#"Find Me"] )
{
[toggleButton setTitle:#"Hide Me" forState:UIControlStateNormal];
mapView.showsUserLocation=YES;
}
else
{
[toggleButton setTitle:#"Find Me" forState:UIControlStateNormal];
mapView.showsUserLocation=NO;
}
}
How to remove these error ?
I want put coordinates of more then one location in my code i want to show loc.png icon on map corresponding to those coordinates how i can accomplish this task?
You can see the sample project from this link: https://drive.google.com/open?id=0B5pNDpbvZ8SnRmNFS0pjVnJFWHc
You are getting compile time error for 3 reasons:
1) The "If" you are using in if-else condition should be "if" i.e lowercase.
2). You have an IBOutlet connect to findMe button in storyboard which do not exist in your view controller. So either remove it or add it.
3)You are using MKMapView but you didn't added the MapKit Framework in "Link Binaries" in build phases option of your project.
Please do all these steps to have your code compiled & executed error free.
Answer to your query:
I want put coordinates of more then one location in my code i want to show loc.png icon on map corresponding to those coordinates how i can accomplish this task?
Here is the code for ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate>
#end
Here is the code for ViewController.m
#import "ViewController.h"
#import "MyAnnotation.h"
#import <MapKit/MapKit.h>
#interface ViewController ()
#property (strong, nonatomic) IBOutlet MKMapView *myMapView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// setup the map view, delegate and current location
[self.myMapView setDelegate:self];
self.myMapView.mapType = MKMapTypeStandard;
CLLocationCoordinate2D myLocation = CLLocationCoordinate2DMake(25.085130,-77.331428);
[self.myMapView setCenterCoordinate:myLocation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(myLocation, 2000, 2000);
region.center = self.myMapView.centerCoordinate;
self.myMapView.showsUserLocation = YES;
[self.myMapView setRegion:region animated:YES];
[self dropPins];
}
-(void)dropPins {
NSMutableArray *annotationArray = [[NSMutableArray alloc] init];
CLLocationCoordinate2D location1 = CLLocationCoordinate2DMake(25.085130, -77.331428);
MyAnnotation *annotation1 = [[MyAnnotation alloc] initWithCoordinates:location1 image:#"loc.png"];
[annotationArray addObject:annotation1];
[self.myMapView addAnnotations:annotationArray];
[annotationArray removeAllObjects];
CLLocationCoordinate2D location2 = CLLocationCoordinate2DMake(25.085130, -77.336428);
MyAnnotation *annotation2 = [[MyAnnotation alloc] initWithCoordinates:location2 image:#"loc.png"];
[annotationArray addObject:annotation2];
[self.myMapView addAnnotations:annotationArray];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
static NSString *identifier = #"MyLocation";
if ([annotation isKindOfClass:[MyAnnotation class]])
{
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[self.myMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView == nil)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
} else
{
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = NO;
if([[(MyAnnotation *)annotationView.annotation image] isEqualToString:#"pin1.png"])
annotationView.image = [UIImage imageNamed:#"loc.png"];
if([[(MyAnnotation *)annotationView.annotation image] isEqualToString:#"pin2.png"])
annotationView.image = [UIImage imageNamed:#"loc.png"];
return annotationView;
}
return nil;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Add new files MyAnnotation.h/MyAnnotation.m
Here is the code for MyAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyAnnotation : NSObject <MKAnnotation>
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy, readonly) NSString *image;
-(id)initWithCoordinates:(CLLocationCoordinate2D) paramCoordinates
image:(NSString *) paramImage;
#end
Here is the code for MyAnnotation.m
#import "MyAnnotation.h"
#implementation MyAnnotation
-(id)initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates
image:(NSString *)paramImage
{
self = [super init];
if(self != nil)
{
_coordinate = paramCoordinates;
_image = paramImage;
}
return (self);
}
#end
Related
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 !
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.
I have this code that displays 4 points on a map with a custom image. I have begun to learn that perhaps the way I structured it is not optimal but it is what I have.
Please help me to learn how to make the titles I created show up on the map with the custom poi when someone taps it.
I have two classes that work with the view. The classes are MapAnnotation and LocationsViewController.
Here is the code for each.
MapAnnotation.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapAnnotation : NSObject <MKAnnotation, MKMapViewDelegate>
{
CLLocationCoordinate2D _coordinate;
NSString * title;
}
#property (nonatomic, copy) NSString *title;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate;
#end
MapAnnotation.m
#import "MapAnnotation.h"
#import "LocationsViewController.h"
#implementation MapAnnotation
#synthesize coordinate = _coordinate;
#synthesize title;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate
{
self = [super init];
if (self != nil)
{
_coordinate = coordinate;
}
return self;
}
#end
LocationsViewController.h
#import "TechBookAppDelegate.h"
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface LocationsViewController : UIViewController <MKMapViewDelegate, MKAnnotation>
{
IBOutlet MKMapView *worldView;
IBOutlet UIActivityIndicatorView *activityIndicator;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id < MKAnnotation >)annotation;
#end
LocationsViewController.m
#import "LocationsViewController.h"
#import "MapAnnotation.h"
#interface LocationsViewController ()
#end
#implementation LocationsViewController
#synthesize coordinate = _coordinate;
#synthesize title;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Initialization code
}
return self;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *AnnotationViewID = #"annotationViewID";
MKAnnotationView *annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
}
annotationView.image = [UIImage imageNamed:#"app_icon_sm.png"];
annotationView.annotation = annotation;
return annotationView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
worldView.showsUserLocation = NO;
CLLocationCoordinate2D wisconsin = {.latitude = 45.620775, .longitude = -89.47844};
CLLocationCoordinate2D pennsyvainia = {.latitude = 39.912417, .longitude = -77.663268};
CLLocationCoordinate2D nevada = {.latitude = 36.054362, .longitude = -115.020470};
CLLocationCoordinate2D texas = {.latitude = 32.555038, .longitude = -94.295592};
MapAnnotation *pinWI = [[MapAnnotation alloc] initWithCoordinate: wisconsin] ;
MapAnnotation *pinPA = [[MapAnnotation alloc] initWithCoordinate: pennsyvainia];
MapAnnotation *pinNV = [[MapAnnotation alloc] initWithCoordinate: nevada];
MapAnnotation *pinTX = [[MapAnnotation alloc] initWithCoordinate: texas];
//UIImage *star = [UIImage imageNamed:#"locations_marker.png"];
//////////////////
pinWI.title = #"Rhinelander, WI";///////
pinPA.title = #"Chambersburg, PA";//////I dont understand why these do not output a
pinNV.title = #"Henderson, NV";/////////title if the title property is a part of the
pinTX.title = #"Marshall, TX";////////// MKAnnotation
//////////////////
[worldView addAnnotation:pinTX];
[worldView addAnnotation:pinNV];
[worldView addAnnotation:pinWI];
[worldView addAnnotation:pinPA];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
I suppose I need a function to create the titles? I really am hoping I do not have to create more classes to do this.
Your main question is:
How to make the titles I created show up on the map with the custom poi when someone taps it.
In the viewForAnnotation delegate method, you need to set the canShowCallout property of the annotation view to YES (the default is NO):
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation...
annotationView.canShowCallout = YES; // <-- add this line
}
Some additional comments unrelated to the question:
In MapAnnotation.h, this class will only be implementing MKAnnotation, not MKMapViewDelegate so remove it from the protocol list to avoid potential compiler warnings and to make the code clearer and cleaner:
#interface MapAnnotation : NSObject <MKAnnotation>
In MapAnnotation.m, you don't need the #import "LocationsViewController.h". Remove it.
In LocationsViewController.h, this class will not be implementing MKAnnotation so remove it from the protocol list to avoid potential compiler warnings and to make the code clearer and cleaner:
#interface LocationsViewController : UIViewController <MKMapViewDelegate>
Also in LocationsViewController.h, it's unnecessary to declare the delegate methods you'll be implementing. You can remove the viewForAnnotation declaration.
In LocationsViewController.m, the #synthesizes for coordinate and title don't belong here. Remove them.
-(void)locatePlaceonMap:(NSDictionary*)dic
{
[map_bar setScrollEnabled:YES];
map_bar.delegate = self;
MKCoordinateRegion zoomIn = map_bar.region;
zoomIn.span.latitudeDelta = 0.1f;
zoomIn.span.longitudeDelta = 0.1f;
zoomIn.center.latitude = ApplicationDelegate.latitude;
zoomIn.center.longitude = ApplicationDelegate.longitude;
[map_bar setRegion:zoomIn animated:NO];
MKPointAnnotation *annotation = [[MKPointAnnotation alloc]init];
annotation.title = [dic valueForKey:#"vName"];
annotation.subtitle = [dic valueForKey:#"t_long_address"];
CLLocationCoordinate2D newlocation = [map_bar.userLocation coordinate];
newlocation.latitude=[[dic valueForKey:#"dLat"]doubleValue];
newlocation.longitude=[[dic valueForKey:#"dLong"]doubleValue];
annotation.coordinate = newlocation;
[map_bar addAnnotation:annotation];
}
#pragma mark MkMapViewDelegate Methods
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation: (id<MKAnnotation>)annotation
{
MKPinAnnotationView *pinView = nil;
static NSString *defaultPinID = #"ReusedPin";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID];
if (annotation == mapView.userLocation) {
return nil;
}else{
pinView.image = [UIImage imageNamed:#"pin_trophy.png"];
pinView.pinColor = MKPinAnnotationColorRed;
}
pinView.canShowCallout = YES;
pinView.animatesDrop = NO;
return pinView;
}
I am trying to create draggable custom pin with Title popup with MapKit. but when I implement viewForAnnotation to make PIN appear as custom image, its disappears pop title as if I youch Pin on map it does not show titla popup,
while if I comments viewForAnnotation it works fine, but I want both things custom image and popup title when tap pin.
below is code
- (void)viewDidLoad
{
MKCoordinateRegion newRegion = MKCoordinateRegionMakeWithDistance(LocCoordinate, 20000, 20000);
DDAnnotation *point = [[DDAnnotation alloc] init];
[point setCoordinate:mapCenter];
[point setTitle:#"Where am I"];
[point setSubtitle:#"I am here"];
[self.mvTripMap addAnnotation:point];
[self.mvTripMap setRegion:newRegion animated:YES];
[super viewDidLoad];
}
-(MKAnnotationView *)mapView:(MKMapView *)MapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *cabAnnotationIdentifier=#"cabAnnotationIdentifier";
MKAnnotationView *annotationView=[MapView dequeueReusableAnnotationViewWithIdentifier:cabAnnotationIdentifier];
if(!annotationView){
annotationView=[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:cabAnnotationIdentifier];
annotationView.image=[UIImage imageNamed:#"start.png"];
annotationView.draggable = YES;
}
return annotationView;
}
DDAnnotation.h
#import <MapKit/MapKit.h>
#interface DDAnnotation : MKPlacemark {
CLLocationCoordinate2D coordinate_;
NSString *title_;
NSString *subtitle_;
}
// Re-declare MKAnnotation's readonly property 'coordinate' to readwrite.
#property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *subtitle;
#end
DDAnnotation.m
#import "DDAnnotation.h"
#implementation DDAnnotation
#synthesize coordinate = coordinate_;
#synthesize title = title_;
#synthesize subtitle = subtitle_;
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate addressDictionary:(NSDictionary *)addressDictionary {
if ((self = [super initWithCoordinate:coordinate addressDictionary:addressDictionary])) {
self.coordinate = coordinate;
}
return self;
}
#end
Just put annotationView.canShowCallout= YES; and it will work
updated code
-(MKAnnotationView *)mapView:(MKMapView *)MapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *cabAnnotationIdentifier=#"cabAnnotationIdentifier";
MKAnnotationView *annotationView=[MapView dequeueReusableAnnotationViewWithIdentifier:cabAnnotationIdentifier];
if(!annotationView){
annotationView=[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:cabAnnotationIdentifier];
annotationView.image=[UIImage imageNamed:#"start.png"];
annotationView.draggable = YES;
annotationView.canShowCallout= YES;
}
return annotationView;
}
I'm having trouble getting the MKAnnotationViews show up on the map in MapKit. I'm using iOS 7, and have now searched the forums and the web for many hours, trying different samples and setups.
Below I have the most basic setup possible (I think) to make it work. The app contains a single ViewController with a toolbar with a button on top, and the rest is the MapView. The button triggers the method zoomToUser:(UIBarButtonItem*)sender. Right-clicking and checking my outlets and delegates seem to be correct. I have some NSLog-statements being triggered to output some debug info.
First the VC:
#import "ViewController.h"
#import "Data.h"
#interface ViewController () <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
- (IBAction)zoomToUser:(UIBarButtonItem *)sender;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.showsUserLocation = YES;
Data *ann = [[Data alloc] init];
[self.mapView addAnnotation:ann];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self zoomToUser:nil];
}
-(IBAction)zoomToUser:(UIBarButtonItem *)sender
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.mapView.userLocation.coordinate, 2000, 2000);
NSLog(#"region: %f x %f",self.mapView.userLocation.coordinate.latitude,self.mapView.userLocation.coordinate.longitude);
[self.mapView setRegion:region animated:YES ];
NSArray *arr = self.mapView.annotations;
for(int i = 0, max = arr.count; i < max; i++)
{
id<MKAnnotation> annotation = arr[i];
NSLog(#"%d of %d: %# (%#)",i+1,max,annotation.title, [annotation class]);
}
}
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
NSString *reuseId = #"Test";
if([annotation isKindOfClass:[MKUserLocation class]])
{
return nil;
}
else if( [annotation isKindOfClass:[Data class]])
{
MKAnnotationView *annov = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if(!annov)
{
annov = [[MKAnnotationView alloc]initWithAnnotation:annotation
reuseIdentifier:reuseId];
}
else
{
annov.annotation = annotation;
}
annov.canShowCallout = YES;
NSLog(#"Title: %#",annotation.title);
return annov;
}
else
{
return nil;
}
}
#end
And the Data class:
#import "Data.h"
#implementation Data
-(NSString *)title
{
return #"The title";
}
-(NSString *)subtitle
{
return #"A subtitle";
}
-(CLLocationCoordinate2D)coordinate
{
CLLocationCoordinate2D coordinate;
coordinate.latitude = 60.123456;
coordinate.longitude = 10.123456;
return coordinate;
}
#end
The Data.h:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface Data : NSObject <MKAnnotation>
#end
And the ViewController.h:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController
#end
As you can see the viewForAnnotation-method prints the annotations title in console when it's requested, and each time the map pans the area, it prints.
Pressing the BarButton and triggering the zoomToUser:-method logs to console that the map indeed has two annotations, the MKUserLocation and the one I added.
How come my MapView tells me it has the annotation, it asks for the view, it gets the view, but it does not show it?
In viewForAnnotation, the code is creating and returning an MKAnnotationView for annotations of type Data.
The MKAnnotationView class, by default, creates an empty view.
That is, its image property is nil and the view basically contains no content.
So, as-is, the annotation views are being created and added but they are invisible.
You can either:
Set the image property on the MKAnnotationView:
annov.image = [UIImage imageNamed:#"something"];
Or, simpler, create an MKPinAnnotationView instead which is a convenient subclass of MKAnnotationView that displays a pin image for you:
MKPinAnnotationView *annov = (MKPinAnnotationView *)[mapView dequeue...
if(!annov)
{
annov = [[MKPinAnnotationView alloc]initWithAnnotation:annotation
reuseIdentifier:reuseId];
annov.pinColor = MKPinAnnotationColorRed; //or Green or Purple
}
else
...
Unrelated:
You've created a custom annotation class Data which is fine but if all you need are the three properties title, subtitle, and coordinate, then you can just use the pre-defined MKPointAnnotation class which lets you set all the properties per-instance:
MKPointAnnotation *ann = [[MKPointAnnotation alloc] init];
ann.title = #"The title";
ann.subtitle = #"A subtitle";
ann.coordinate = CLLocationCoordinate2DMake (60.123456, 10.123456);
[self.mapView addAnnotation:ann];
I would like to have a MKMapView showing annotations with disclosure-buttons which lead to a view controller like the Golden Gate Bridge annotation in this Apple sample app.
I load the coordinates from a plist and the annotations appear correctly with title/subtitle but the method
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
has no effect.
I guess that I somehow have to link the annotations with the pinannotations?
MapViewController.h:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "Annotation.h"
#interface MapViewController : UIViewController<CLLocationManagerDelegate, MKMapViewDelegate>
#property (strong, nonatomic) CLLocationManager *location;
#property (nonatomic, retain) NSArray *data;
#end
MapViewController.m:
#import "MapViewController.h"
#interface MapViewController ()
#property (nonatomic, weak) IBOutlet MKMapView *mapView;
#end
#implementation MapViewController
#synthesize data;
#synthesize location, minLatitude, maxLatitude, minLongitude, maxLongitude;
- (void)viewDidLoad
{
NSString *dataPath = [[NSBundle mainBundle] pathForResource:#"City" ofType:#"plist"];
self.data = [NSArray arrayWithContentsOfFile:dataPath];
for (int i = 0; i < data.count; i++) {
NSDictionary *dataItem = [data objectAtIndex:i];
//Create Annotation
Annotation *building = [[Annotation alloc] init];
building.title = [dataItem objectForKey:#"Title"];
building.subtitle = [dataItem objectForKey:#"Subtitle"];
MKCoordinateRegion buildingcoordinates = { {0.0, 0.0}, {0.0, 0.0} };
buildingcoordinates.center.latitude = [[dataItem objectForKey:#"Latitude"] floatValue];
buildingcoordinates.center.longitude = [[dataItem objectForKey:#"Longitude"] floatValue];
building.coordinate = buildingcoordinates.center;
[self.mapView addAnnotation:building];
}
[super viewDidLoad];
}
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString *pinIdentifier = #"pinIndentifier";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)
[self.mapView dequeueReusableAnnotationViewWithIdentifier:pinIdentifier];
if (pinView == nil)
{
// if an existing pin view was not available, create one
MKPinAnnotationView *customPinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:pinIdentifier];
customPinView.pinColor = MKPinAnnotationColorPurple;
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
return customPinView;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
Annotation.h:
#import <Foundation/Foundation.h>
#import <MapKit/MKAnnotation.h>
#interface Annotation : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
}
#property(nonatomic, assign) CLLocationCoordinate2D coordinate;
#property(nonatomic, copy) NSString *title;
#property(nonatomic, copy) NSString *subtitle;
#end
Annotation.m:
#import "Annotation.h"
#implementation Annotation
#synthesize coordinate, title, subtitle;
#end
Most likely the map view's delegate is not set which means the viewForAnnotation delegate method will not get called.
Since you've declared mapView as an IBOutlet, in the xib, make sure that the map view's delegate is connected to File's Owner.
Alternatively, at the top of the viewDidLoad method in MapViewController, set it programmatically:
mapView.delegate = self;