MBXMapKit Overlays Are Not Working - ios

I'm trying to use MapBox's MBXMapKit to add a custom style to my map. I've followed the sample app and the docs but I keep seeing the standard MapKit UI.
Am I missing something glaringly obvious here? I've added the protocol methods from the SampleApp # MBXMapBox GitHub, and added a MBXRasterTileOverlay as I should... So I'm not really sure what's missing.
//
// MapViewController.h
//
#import <UIKit/UIKit.h>
#import "MapKit/MapKit.h"
#import "MBXMapKit.h"
#interface MapViewController : UIViewController <MKMapViewDelegate, MBXRasterTileOverlayDelegate>
#end
|
//
// MapViewController.m
//
#import "MapViewController.h"
#interface MapViewController ()
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#end
#implementation MapViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self setUpNavigationBarView];
MBXRasterTileOverlay *blah = [[MBXRasterTileOverlay alloc] initWithMapID:#"sparkyrobinson.jp6f81f2" includeMetadata:YES includeMarkers:YES];
MBXRasterTileOverlay *rasterOverlay = [[MBXRasterTileOverlay alloc] initWithMapID:#"sparkyrobinson.jp6f81f2"];
rasterOverlay.delegate = self;
[self.mapView addOverlay:blah];
}
- (void) setUpNavigationBarView
{
UINavigationBar *navigationBar = self.navigationController.navigationBar;
[navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
navigationBar.shadowImage = [UIImage new];
navigationBar.translucent = YES;
navigationBar.titleTextAttributes = #{
NSForegroundColorAttributeName: UIColorFromRGB(TURQUOISE),
};
}
#pragma mark - MKMapViewDelegate protocol implementation
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
// This is boilerplate code to connect tile overlay layers with suitable renderers
//
if ([overlay isKindOfClass:[MBXRasterTileOverlay class]])
{
MKTileOverlayRenderer *renderer = [[MKTileOverlayRenderer alloc] initWithTileOverlay:overlay];
return renderer;
}
return nil;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
// This is boilerplate code to connect annotations with suitable views
//
if ([annotation isKindOfClass:[MBXPointAnnotation class]])
{
static NSString *MBXSimpleStyleReuseIdentifier = #"MBXSimpleStyleReuseIdentifier";
MKAnnotationView *view = [mapView dequeueReusableAnnotationViewWithIdentifier:MBXSimpleStyleReuseIdentifier];
if (!view)
{
view = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:MBXSimpleStyleReuseIdentifier];
}
view.image = ((MBXPointAnnotation *)annotation).image;
view.canShowCallout = YES;
return view;
}
return nil;
}
#pragma mark - MBXRasterTileOverlayDelegate implementation
- (void)tileOverlay:(MBXRasterTileOverlay *)overlay didLoadMetadata:(NSDictionary *)metadata withError:(NSError *)error
{
// This delegate callback is for centering the map once the map metadata has been loaded
//
if (error)
{
NSLog(#"Failed to load metadata for map ID %# - (%#)", overlay.mapID, error?error:#"");
}
else
{
[self.mapView mbx_setCenterCoordinate:overlay.center zoomLevel:overlay.centerZoom animated:NO];
}
}
- (void)tileOverlay:(MBXRasterTileOverlay *)overlay didLoadMarkers:(NSArray *)markers withError:(NSError *)error
{
// This delegate callback is for adding map markers to an MKMapView once all the markers for the tile overlay have loaded
//
if (error)
{
NSLog(#"Failed to load markers for map ID %# - (%#)", overlay.mapID, error?error:#"");
}
else
{
[self.mapView addAnnotations:markers];
}
}
- (void)tileOverlayDidFinishLoadingMetadataAndMarkers:(MBXRasterTileOverlay *)overlay
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
#end
Cheers.

Everything looks good. Are you sure that the self.mapView outlet is hooked up and you're not adding an overlay to nil?

Related

Storing Data in Annotation and Displaying on a Custom Callout but Data Changes to the Most Recent Update

So, I've created a custom callout that appears over the selected annotation. Everything works exactly how I want--the only problem is after I've dropped another pin of the same type, then all the past pins will display the same information. For example, I may have a pin drop that displays in the callout "McDonalds" and the next pin that drops displays "Starbucks". Now all my previously dropped pins will display "Starbucks".
I'm currently attempting to store information in the annotation's subtitle property and then displaying that through a formatted string onto my custom UIView's Label...It works but I need the annotation's information to never change. There must be something I'm missing or do not understand. Any help will be much appreciated.
I've posted all the code I believe to be relevant below. Thank you!
Custom Callout.h
#import <UIKit/UIKit.h>
#interface PinView : UIView
{
UIView *view;
UILabel *theValueLabel;
}
#property (nonatomic, retain) IBOutlet UIView *view;
#property (nonatomic, retain) IBOutlet UILabel *theValueLabel;
#end
Custom Callout.m
#import "PinView.h"
#implementation PinView
#synthesize theValueLabel;
#synthesize view;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
UIView *nib = [[[UINib nibWithNibName:#"customView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0];
[self addSubview:nib];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
if (self.subviews.count == 0) {
UIView *nib = [[[UINib nibWithNibName:#"customView" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0];
[self addSubview:nib];
}
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self setup];
}
- (void)setup {
self.theValueLabel.text = #"foo";
}
in my main View Controller.m
#interface BreadTrailViewController ()<CLLocationManagerDelegate, MKMapViewDelegate, MFMailComposeViewControllerDelegate>
{
PinView *aView
MKPointAnnotation *Pin1;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
if (location != nil)
{
Pin1 = [[MKPointAnnotation alloc] init];
Pin1.title = #"Venue";
Pin1.subtitle = [NSString stringWithFormat:#"Venue Name: %#\n%f,%f\nAddress: %#",revGeocodeVenue, lat, lng, revGeocodeAddress];
Pin1.coordinate = location.coordinate;
[self.mapView addAnnotation:Pin1];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
MKPinAnnotationView *pinView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"CustomPinAnnotationView"];
if (!pinView)
{
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"CustomPinAnnotationView"];
pinView.canShowCallout = NO;
} else {
pinView.annotation = annotation;
}
if ([[annotation title] containsString:#"Venue"])
{
pinView.pinTintColor = [UIColor greenColor];
}
return pinView;
}
return nil;
}
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
aView = [[PinView alloc] initWithFrame:CGRectMake( 0, 0, 300, 350)];
aView.layer.cornerRadius = 20;
aView.layer.masksToBounds = YES;
aView.center = CGPointMake(view.bounds.size.width*0.5f, -aView.bounds.size.height*0.35f);
//Using the Pin's subtitle to store the data string and display on PinView
if ([[view.annotation title] containsString:#"Venue"])
{
aView.theValueLabel.text = Pin1.subtitle;
}
[view addSubview:aView];
}
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
[aView removeFromSuperview];
}
I found the problem! I was using Pin1.subtitle when what I should be using is view.annotation.subtitle--everything is working perfectly now. I hope this helps someone else!
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
aView = [[PinView alloc] initWithFrame:CGRectMake( 0, 0, 300, 350)];
aView.layer.cornerRadius = 20;
aView.layer.masksToBounds = YES;
aView.center = CGPointMake(view.bounds.size.width*0.5f, -aView.bounds.size.height*0.35f);
//Using the Pin's subtitle to store the data string and display on PinView
if ([[view.annotation title] containsString:#"Venue"])
{
aView.theValueLabel.text = view.annotation.subtitle;
}
[view addSubview:aView];
}

Set label or text field to annotation title

Edit: Original Statement:
I have a navigation controller embedded with a mapView on one view controller and it push segues into a second view controller by the use of a callout. The User hits the info key on the callout and they segue into the second view controller where they have to fill out a form. Once they hit the back key in the second view controller navigation bar, how would I link the first two lines of the form they filled out to be the title and subtitle of the pin?
Update: I've gone mad, because I have googled and re-made my XCode project to fulfill this one objective. I don't like to leave tasks uncompleted. I am getting nil for my string and text field when I return back towards the first view controller.
first view controller.h file
#import <UIKit/UIKit.h>
#import "mapKit/Mapkit.h"
#import "thePinsViewController.h"
#interface ViewController : UIViewController <MKMapViewDelegate, MKAnnotation, thePinsViewController> {
MKMapView *mapViewing;
MKPointAnnotation *annot;
}
#property(nonatomic, retain) IBOutlet MKMapView *mapViewing;
#end
first view controller.m file
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize coordinate = _coordinate;
// This is your IBOutlet
#synthesize mapViewing;
// Initiate when the user holds the map to place a pin
- (void) addGestureRecognizerToMapView {
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
// User needs to press for [insert number in decimal format] seconds
lpgr.minimumPressDuration = 1.0;
[mapViewing addGestureRecognizer:lpgr];
}
// This method fires when you add a pin
- (void)handleLongPress:(UIGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateBegan) {
return;
}
CGPoint touchPoint = [gestureRecognizer locationInView: mapViewing];
CLLocationCoordinate2D touchMapCoordinate = [mapViewing convertPoint:touchPoint toCoordinateFromView:mapViewing];
annot = [[MKPointAnnotation alloc] init];
annot.title = #"a";
annot.subtitle = #"SubTitle";
annot.coordinate = touchMapCoordinate;
[mapViewing addAnnotation:annot];
}
// This is your manual callout box
// with a rightDisclosureButton embedded in it
- (MKAnnotationView *)mapView:(MKMapView *)sender viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#""];
// This gives the user permission to see or not see the callout box
annotationView.canShowCallout = YES;
// This is the info button in the callout box
UIButton *rightDisclosureButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
annotationView.rightCalloutAccessoryView = rightDisclosureButton;
return annotationView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
thePinsViewController *scoobydoo = [[thePinsViewController alloc] init];
[self performSegueWithIdentifier:#"heylisten" sender:view];
scoobydoo.delegate = self;
}
- (void) didFirstFieldChange:(NSString*)newValue{
// Change your annotation title here
annot.title = newValue;
}
- (void) didSecondFieldChange:(NSString*)newValue{
// Change your annotation title here
annot.subtitle = newValue;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[mapViewing setDelegate:self];
[self addGestureRecognizerToMapView];
}
second view controller.h file
#import <UIKit/UIKit.h>
#protocol thePinsViewController <NSObject>
- (void) didFirstFieldChange:(NSString*)newValue;
- (void) didSecondFieldChange:(NSString*)newValue;
#end
#interface thePinsViewController : UIViewController
#property (nonatomic, weak) id<thePinsViewController> delegate;
#property(nonatomic, strong) IBOutlet UITextField *helloWorldTextField;
#property(nonatomic, strong) IBOutlet UITextField *helloWorldTextField2;
#property(nonatomic, strong) NSString *helloWorldString;
#end
second view controller.m file
#import "thePinsViewController.h"
#interface thePinsViewController ()
#end
#implementation thePinsViewController
#synthesize helloWorldTextField;
#synthesize helloWorldTextField2;
#synthesize helloWorldString;
- (void) firstFieldChanged{
if ( [self.delegate performSelector:#selector(didFirstFieldChange:)] ){
[self.delegate didFirstFieldChange:helloWorldTextField.text];
}
}
- (void) secondFieldChanged{
if ( [self.delegate performSelector:#selector(didSecondFieldChange:)] ){
[self.delegate didSecondFieldChange:helloWorldTextField2.text];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
helloWorldString = helloWorldTextField.text;
}
You should add a delegate pattern to pass the info from your second view controller back to your first view controller.
PinInformationViewController.h
#protocol PinInformationViewControllerProtocol <NSObject>
- (void) didFirstFieldChange:(NSString*)newValue;
- (void) didSecondFieldChange:(NSString*)newValue;
#end
#interface PinInformationViewController : UIViewController
#property (nonatomic, weak) id<PinInformationViewControllerProtocol> delegate;
#end
PinInformationViewController.m
- (void) firstFieldChanged{
if ( [self.delegate performSelector:#selector(didFirstFieldChange:)] ){
[self.delegate didFirstFieldChange:myTextField.text];
}
}
- (void) secondFieldChanged{
if ( [self.delegate performSelector:#selector(didSecondFieldChange:)] ){
[self.delegate didSecondFieldChange:myOtherTextField.text];
}
}
FirstViewController.m
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
pinInformationViewController *scoobydoo = [[pinInformationViewController alloc]init];
scoobydoo.delegate = self;
annot.title = scoobydoo.helloWorldString;
[self performSegueWithIdentifier:#"heylisten" sender:view];
}
- (void) didFirstFieldChange:(NSString*)newValue{
// Change your annotation title here
}
- (void) didSecondFieldChange:(NSString*)newValue{
// Change your annotation subtitle here
}

MapKit Annotations not showing up on map

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];

MKMapView Delegate Methods not working

I just wanted to add a Polyline to my Map which is displayed in a tableviewcell. Unfortunately
the delegate methods are not called... Would be nice if someone knows why.
My tableview.h:
#import <UIKit/UIKit.h>
#import "Route.h"
#import <MapKit/MapKit.h>
#import <QuartzCore/QuartzCore.h>
#interface RoutesDetailView : UITableViewController<MKMapViewDelegate>{
Route *myRoute;
MKMapView *mapView;
// the view we create for the line on the map
MKPolylineView* _routeLineView;
// the rect that bounds the loaded points
MKMapRect _routeRect;
MKPolyline* _routeLine;
}
#property (nonatomic, retain) Route *myRoute;
#property (nonatomic,retain) MKMapView *mapView;
#property (nonatomic, retain) MKPolyline* routeLine;
#property (nonatomic, retain) MKPolylineView* routeLineView;
-(MKPolyline *) loadRoute: (Route *) theRoute;
#end
And my tableview.m:
#implementation RoutesDetailView
#synthesize myRoute,mapView;
#synthesize routeLine = _routeLine;
#synthesize routeLineView = _routeLineView;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
MKMapView *myMap = [[MKMapView alloc] initWithFrame:CGRectMake(10, 1, 300 , 300)];
myMap.layer.cornerRadius = 10.0;
[self setMapView:myMap];
[mapView setDelegate:self];
CLLocationCoordinate2D annotationCoord;
annotationCoord.latitude = [[NSString stringWithFormat:#"%#",NSLocalizedString(#"DefaultPointLAT", nil)] doubleValue];
annotationCoord.longitude = [[NSString stringWithFormat:#"%#",NSLocalizedString(#"DefaultPointLONG", nil)] doubleValue];
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
annotationPoint.coordinate = annotationCoord;
MKCoordinateRegion region =
MKCoordinateRegionMakeWithDistance (annotationPoint.coordinate,[[NSString stringWithFormat:#"%#",NSLocalizedString(#"DefaultCircle", nil)] doubleValue], [[NSString stringWithFormat:#"%#",NSLocalizedString(#"DefaultCircle", nil)] doubleValue]);
[mapView setRegion:region animated:NO];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
.
.
.
static NSString *CellIdentifier = #"CellMap";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[mapView setFrame:CGRectMake(10, 1, cell.frame.size.width-20 , cell.frame.size.height-1)];
[cell addSubview:mapView];
[mapView addOverlay:[self loadRoute:myRoute]];
return cell;
.
.
.
}
#pragma mark - Table view delegate
-(MKPolyline *) loadRoute: (Route *) theRoute
{
MKMapPoint northEastPoint;
MKMapPoint southWestPoint;
// create a c array of points.
MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * theRoute.latitude.count);
for(int idx = 0; idx < theRoute.latitude.count; idx++)
{
CLLocationDegrees latitude = [[[theRoute latitude] objectAtIndex:idx] doubleValue];
CLLocationDegrees longitude = [[[theRoute longitude] objectAtIndex:idx] doubleValue];
// create our coordinate and add it to the correct spot in the array
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);
MKMapPoint point = MKMapPointForCoordinate(coordinate);
//
// adjust the bounding box
//
// if it is the first point, just use them, since we have nothing to compare to yet.
if (idx == 0) {
northEastPoint = point;
southWestPoint = point;
}
else
{
if (point.x > northEastPoint.x)
northEastPoint.x = point.x;
if(point.y > northEastPoint.y)
northEastPoint.y = point.y;
if (point.x < southWestPoint.x)
southWestPoint.x = point.x;
if (point.y < southWestPoint.y)
southWestPoint.y = point.y;
}
pointArr[idx] = point;
}
// create the polyline based on the array of points.
self.routeLine = [MKPolyline polylineWithPoints:pointArr count:theRoute.latitude.count];
_routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);
// clear the memory allocated earlier for the points
free(pointArr);
return self.routeLine;
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay
{
NSLog(#"DELEGATE CALL");
MKOverlayView* overlayView = nil;
if(overlay == self.routeLine)
{
//if we have not yet created an overlay view for this overlay, create it now.
if(nil == self.routeLineView)
{
self.routeLineView = [[MKPolylineView alloc] initWithPolyline:self.routeLine];
self.routeLineView.fillColor = [UIColor redColor];
self.routeLineView.strokeColor = [UIColor redColor];
self.routeLineView.lineWidth = 15;
}
overlayView = self.routeLineView;
}
return overlayView;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
*/
}
#end
Try this, I was having the same issue. After trying many combinations this is the one which works.
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController<MKMapViewDelegate> {
MKMapView *mapView;
}
and the implementation...
- (void)viewDidLoad {
[super viewDidLoad];
mapView = [[MKMapView alloc] initWithFrame: CGRectMakeFullScreenIphone];
mapView.delegate = self;
[mapView setMapType: MKMapTypeStandard];
[self.view addSubview: mapView];
MKCoordinateRegion newRegion;
// configure region...
[mapView setRegion:newRegion animated:YES];
CLLocationCoordinate2D coordinate;
//configure coordinate...
MKPointAnnotation *annotation = [[MKPointAnnotation alloc]init];
[annotation setCoordinate:coordinate];
[annotation setTitle:#"TEST"];
[mapView addAnnotation:annotation];
}
The simple code above works fine and delegate's methods were called.
if you are running the application in simulator, then the
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay
this delegate method will not get called, you need to run it on iOS Device.
The first Meth is
mapView:regionDidChangeAnimated:
and the second is
mapView:didUpdateUserLocation:
Header File
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (weak, nonatomic) IBOutlet UIButton *searchButton;
#end
Implementation File
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
self.mapView.mapType = MKMapTypeStandard;
self.mapView.showsUserLocation = YES;
self.searchButton.hidden = YES;
}
- (IBAction)setMapType:(UISegmentedControl *)sender {
switch (sender.selectedSegmentIndex) {
case 0:
self.mapView.mapType = MKMapTypeStandard;
break;
case 1:
self.mapView.mapType = MKMapTypeSatellite;
break;
case 2:
self.mapView.mapType = MKMapTypeHybrid;
break;
default:
break;
}
}
- (IBAction)zoomToCurrentLocation:(UIBarButtonItem *)sender {
float spanX = 0.00725;
float spanY = 0.00725;
MKCoordinateRegion region;
region.center.latitude = self.mapView.userLocation.coordinate.latitude;
region.center.longitude = self.mapView.userLocation.coordinate.longitude;
region.span.latitudeDelta = spanX;
region.span.longitudeDelta = spanY;
self.searchButton.hidden = YES;
[self.mapView setRegion:region animated:YES];
}
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
self.searchButton.hidden = NO;
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
[self.mapView setCenterCoordinate:userLocation.coordinate animated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end

Trouble changing color of the pin iOS MapKit

I'm having trouble changing the pinColor for an annotation in MapKit. When I don't try to implement the mapView:viewForAnnotation: method everything works (the annotation is added) but when I try to change the annotation view, the simulator crashes :
Here is the code :
MapViewController.h
#import "MapViewController.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "Annotation.h"
#implementation MapViewController
#synthesize myMapView;
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
}
return self;
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
CLLocationCoordinate2D location;
location.longitude = 2.21;
location.latitude = 48.5;
MKCoordinateSpan span;
span.latitudeDelta = 1*(1 - 0);
span.longitudeDelta = 1*(1 - 0);
MKCoordinateRegion region;
region.span = span;
region.center = location;
[myMapView setRegion:region animated:NO];
[myMapView regionThatFits:region];
Annotation *someAnnotation =[[Annotation alloc] init];
[myMapView addAnnotation:someAnnotation];
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (MKAnnotationView *) mapView:(MKMapView *) mapView viewForAnnotation:(id<MKAnnotation>) annotation {
MKPinAnnotationView *customPinview = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil] autorelease];
customPinview.pinColor = MKPinAnnotationColorGreen;
customPinview.animatesDrop = YES;
customPinview.canShowCallout = YES;
return customPinview;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
MapViewController.m
//
// MapViewController.h
// TestMap
//
// Created by Johan Ismael on 10/21/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface MapViewController : UIViewController<MKMapViewDelegate> {
#private
IBOutlet MKMapView *myMapView;
}
#property (nonatomic, retain) IBOutlet MKMapView *myMapView;
//- (MKAnnotationView *) mapView:(MKMapView *) mapView viewForAnnotation:(id<MKAnnotation>) annotation;
#end
Thanks in advance !!!
Note : MapViewController is declared as the delegate of the MapView in IB
In the viewForAnnotation method, the alloc is being done on MKAnnotationView instead of MKPinAnnotationView. It must be crashing with "unrecognized selector" because MKAnnotationView doesn't have a pinColor property. Change the alloc to:
MKPinAnnotationView *customPinview = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:nil] autorelease];

Resources