Having scanned all the similar problems and tried all possible solutions, I still can't find the solution to my case. I tried to put multiple pins on my MapView but it seems that my pin can't be added normally. I started a NSTimer in my viewDidLoad method so that every 5 seconds, some updated pins will be put on Map. I added debugging information and found the problem was the that the method viewForAnnotation is not getting called.
(I've already set the delegate by calling [_map setDelegate:self])
My code is as following:
- (void)viewDidLoad
{
[super viewDidLoad];
_map = [[MKMapView alloc] initWithFrame:[[self view] frame]];
[_map setDelegate:self];
CLLocationCoordinate2D startLocation;
startLocation.latitude = [startLat floatValue];
startLocation.longitude = [startLong floatValue];
MKCoordinateSpan span = MKCoordinateSpanMake(0.002, 0.002);
MKCoordinateRegion region = MKCoordinateRegionMake(startLocation, span);
[_map setRegion:region];
[[self view] addSubview:_map];
[self getPlacesForLocation:[_map centerCoordinate]];
NSTimer *currentTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(theActionMethod:) userInfo:nil repeats:YES];
[currentTimer fire];
}
The getPlacesForLocationMethod:
-(void)getPlacesForLocation:(CLLocationCoordinate2D)location
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
{
/* get data from the website
** get the geo information and put them in the MapPin struct
*/
[self putPinsOnMap];
}
}
putPinsOnMap:
-(void)putPinsOnMap
{
for(Pinfo *iter in [_PinfoArray copy])
{
MapPin *pin = [[MapPin alloc] init];
[pin setTitle:[iter from_user_name]];
[pin setSubtitle:[iter text]];
[pin setCoordinate:[iter location]];
//NSLog(#"The coordinate is %f %f", [pin coordinate].latitude, [pin coordinate].longitude);
[_map addAnnotation:pin];
/****************************************/
NSLog(#"Try to put the pin on Map");
/****************************************/
}
}
And here is the content of my MapPin.h:
#interface MapPin : NSObject<MKAnnotation>
#property (nonatomic, copy) NSString *title, *subtitle;
#property (nonatomic) CLLocationCoordinate2D coordinate;
#end
If I stay in place, then every time the (void)putPinsOnMap gets called, it prints "Try to put pin on Map" but the viewForAnnotation method is not getting called (I also added debugging info there but none of them are printed). Only a few times, the method viewForAnnotation sometimes will be called if I zoom out to a great extent.
You say you added debugging info to viewForAnnotation, but you haven't subclassed MKMapView to override the viewForAnnotation method (or at least, you are allocating an MKMapView, not any subclass). I think you are looking for the delegate method:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;
and if you implement that method in your view controller (which you are making the delegate of the MKMapView) you might get useful information.
If mapView:viewForAnnotation: is still not called except when you zoom way out then you have probably placed your annotations incorrectly and they're just way out on some other part of the globe than the one you have initially on screen.
Related
I am trying to make a map, where I can see my current location, and see what the street is called.
so far, I am able to put a pin on my map, but for some reason, I am not getting the callout.
and I have put a NSLog in my viewForAnnotation method, but it is not being called, so i wasn't able to test it.
can someone help me?
-(void)lat:(float)lat lon:(float)lon
{
CLLocationCoordinate2D location;
location.latitude = lat;
location.longitude = lon;
NSLog(#"Latitude: %f, Longitude: %f",location.latitude, location.longitude);
//One location is obtained.. just zoom to that location
MKCoordinateRegion region;
region.center=location;
//Set Zoom level using Span
MKCoordinateSpan span;
span.latitudeDelta=.005f;
span.longitudeDelta=.005f;
region.span=span;
[map setRegion:region animated:TRUE];
//MKReverseGeocoder *geocoder=[[MKReverseGeocoder alloc] initWithCoordinate:location];
//geocoder.delegate=self;
//[geocoder start];
if (cPlacemark != nil) {
[map removeAnnotation:cPlacemark];
}
cPlacemark=[[CustomPlacemark alloc] initWithCoordinate:location];
cPlacemark.title = mPlacemark.thoroughfare;
cPlacemark.subtitle = mPlacemark.locality;
[map addAnnotation:cPlacemark];
[cPlacemark release];
[mLocationManager stopUpdatingLocation];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// try to dequeue an existing pin view first
if ([annotation isKindOfClass:[CustomPlacemark class]]){
MKPinAnnotationView *pinView=(MKPinAnnotationView *)[map dequeueReusableAnnotationViewWithIdentifier:#"customIdentifier"];
if (!pinView)
{
// if an existing pin view was not available, create one
MKPinAnnotationView* cPinAnnoView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:#"customIdentifier"] autorelease];
cPinAnnoView.pinColor = MKPinAnnotationColorPurple;
cPinAnnoView.animatesDrop = YES;
cPinAnnoView.canShowCallout = YES;
// Add button
UIButton *leftButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[leftButton addTarget:self action:#selector(annotationViewClick:) forControlEvents:UIControlEventTouchUpInside];
cPinAnnoView.leftCalloutAccessoryView = leftButton;
} else
{
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
Right now I have customized my viewForAnnotation to be like this.
But I still can't get a callout from my pin and the pin remains red.
But it should be purple of nothing at all
I had the same problem which was not setting the MapView delegate to the File Owner.
Open your nib
Right click on the MapView
Drag the delegate to the File's Owner
I had the same problem, as you mentioned. The delegate had been set to ViewController, but the viewForAnnotation selector was not being called. After some checks, I realized if you do not call addAnotation in the main thread, mapView would not call viewForAnnotation, so following update resolved my problem:
Before:
[_mMapView addAnnotation:marker];
After:
dispatch_async(dispatch_get_main_queue(), ^{
[_mMapView addAnnotation:marker];
});
In order to get the viewForAnnotation to be called, add mapView.delegate=self; to e.g. the viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
mapView.delegate=self;
}
Could it be that your annotation has been added outside the current view area of the MKMapView?
For storyboard, Ctl drag the MKMapView to the orange circle on the bottom bar of ViewController, and select delegate.
This will solve the problem.
As vatrif mentioned in the comments, you must set your delegate BEFORE adding annotations to your MKMapView object.
Others have already explained, odds are high you have not connected your mapview delegate to your controller. Its the first thing to check
i have been working in ios 9 Mapview related app and I experienced the same problem.
somehow I solved my problem, in my case im resizing the mapview.
I added delegate after i resize the mapview. it works now perfectly.!
After having set the delegate for the mapview if still the viewforannotation not getting called then this is something which you have missed - set the self.mapView.showsUserLocation to YES, in interface builder you can tick the shows userLocation option in attributes inspector.
I am using showAnnotations method to show my markers on MKMapView in iOS7 .Sometimes it works perfectly and show all annotation but sometimes it give EXEC_BAD_ACCESS error.
Here is my code.
NSArray *annotations = MapView.annotations;
_mapNeedsPadding = YES;
[MapView showAnnotations:annotations animated:YES];
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
if(_mapNeedsPadding){
[mapView setVisibleMapRect:mapView.visibleMapRect edgePadding:UIEdgeInsetsMake(100, 20, 10, 10) animated:YES];
_mapNeedsPadding = NO;
}
}
In the code shown, you are getting EXC_BAD_ACCESS because calling setVisibleMapRect causes regionDidChangeAnimated to be called by the map view again which starts an infinite recursion.
Even though you are using the boolean flag _mapNeedsPadding to possibly prevent this recursion, the problem is that the flag is being set to NO after setVisibleMapRect has already been called (and it has already called regionDidChangeAnimated and the flag never gets set to NO).
So your code calls setVisibleMapRect which causes regionDidChangeAnimated to get called again resulting in infinite recursion resulting in stack overflow resulting in EXC_BAD_ACCESS.
The "quick fix" is to set _mapNeedsPadding before calling setVisibleMapRect:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
if(_mapNeedsPadding){
_mapNeedsPadding = NO; // <-- call BEFORE setVisibleMapRect
[mapView setVisibleMapRect:mapView.visibleMapRect edgePadding:UIEdgeInsetsMake(100, 20, 10, 10) animated:YES];
}
}
However, I don't recommend this approach to begin with.
Instead, you should manually calculate an MKMapRect based on the annotations you want to show and call setVisibleMapRect:edgePadding:animated: from the main code (instead of showAnnotations:animated:).
And, don't implement or do anything in regionDidChangeAnimated.
Example:
NSArray *annotations = MapView.annotations;
//_mapNeedsPadding = YES;
//[MapView showAnnotations:annotations animated:YES];
MKMapRect rectForAnns = MKMapRectNull;
for (id<MKAnnotation> ann in annotations)
{
MKMapPoint annPoint = MKMapPointForCoordinate(ann.coordinate);
MKMapRect annRect = MKMapRectMake(annPoint.x, annPoint.y, 1, 1);
if (MKMapRectIsNull(rectForAnns))
rectForAnns = annRect;
else
rectForAnns = MKMapRectUnion(rectForAnns, annRect);
}
UIEdgeInsets rectInsets = UIEdgeInsetsMake(100, 20, 10, 10);
[MapView setVisibleMapRect:rectForAnns edgePadding:rectInsets animated:YES];
//Do NOT implement regionDidChangeAnimated...
//- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
// if(_mapNeedsPadding){
// [mapView setVisibleMapRect:mapView.visibleMapRect edgePadding:UIEdgeInsetsMake(100, 20, 10, 10) animated:YES];
// _mapNeedsPadding = NO;
// }
//}
So I want to display where my app's user walked on a MKMapView, I collect datas with the following code :
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
// calc. distance walked
CLLocationDistance meters = [newLocation distanceFromLocation:oldLocation];
self.totalMetters += meters;
[[self labelDistance] setText:[self formatDistanceIntoString:self.totalMetters]];
// create another annotation
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.coordinate = newLocation.coordinate;
// Also add to our map so we can remove old values later
[self.locations addObject:annotation];
// Remove values if the array is too big
while (self.locations.count > 100)
{
annotation = [self.locations objectAtIndex:0];
[self.locations removeObjectAtIndex:0];
// Also remove from the map
[self.map removeAnnotation:annotation];
}
Once it's finished, I call my draw method :
[self drawRoute];
Which contains the following :
- (void)drawRoute {
NSLog(#"drawRoute");
NSInteger pointsCount = self.locations.count;
CLLocationCoordinate2D pointsToUse[pointsCount];
for(int i = 0; i < pointsCount; i++) {
MKPointAnnotation *an = [self.locations objectAtIndex:i];
pointsToUse[i] = CLLocationCoordinate2DMake(an.coordinate.latitude,an.coordinate.latitude);
}
MKPolyline *myPolyline = [MKPolyline polylineWithCoordinates:pointsToUse count:pointsCount];
[self.map addOverlay:myPolyline];
}
Finally my mapView delegate :
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
NSLog(#"route");
if ([overlay isKindOfClass:MKPolyline.class]) {
MKPolylineView *lineView = [[MKPolylineView alloc] initWithOverlay:overlay];
lineView.strokeColor = [UIColor greenColor];
return lineView;
}
return nil;
}
Obviously my controller is MKMapView Delegate conform
#interface NewWalkViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate>
And the mapView in the Storyboard is linked to the controller (outlet and delegate)
I use the "bike road" debug tool and there is the output :
2014-01-25 20:27:30.132 The walking dog[2963:70b] new location : 37.330435
2014-01-25 20:27:30.133 The walking dog[2963:70b] drawRoute
As I can see the method for drawing the overlay is never called, and I don't have a single clue how to fix it.
The main problem is that in drawRoute, this line is passing latitude for both parameters to CLLocationCoordinate2DMake:
pointsToUse[i] = CLLocationCoordinate2DMake
(an.coordinate.latitude,an.coordinate.latitude);
This results in the line being drawn in a different part of the world than where the actual an.coordinate is. For example, if an.coordinate is 37,-122 (somewhere near San Francisco), the line is being drawn instead at 37,37 (somewhere in southern Turkey).
Since you are not actually positioning the map at the wrong location (you are looking for the line at the "right" location), viewForOverlay is never called because the map only calls it when it's possible that the overlay will be visible.
Change that line to:
pointsToUse[i] = CLLocationCoordinate2DMake
(an.coordinate.latitude,an.coordinate.longitude);
or simply:
pointsToUse[i] = an.coordinate;
As James Frost mentions in the comments, as of iOS 7, you should be using rendererForOverlay instead of viewForOverlay though the map view will still call viewForOverlay in iOS 7 if rendererForOverlay has not been implemented. Though this isn't preventing your overlay from displaying in the current case, you should implement the new delegate method as well as the old one (if the iOS 7 app will also be running on iOS 6 or earlier).
Another important but unrelated issue is that you are unnecessarily creating multiple, overlapping overlays. In drawRoute, since the overlay you are creating includes all the locations, you should remove any existing overlays before adding the new one. Otherwise, the map ends up with an overlay for location 0 to 1, an overlay for location 0 to location 2, an overlay for location 0 to location 3, etc. The previous overlays are not obviously visible since they have the same color and line width. Before the addOverlay line, put:
[self.map removeOverlays:self.map.overlays];
After posting on Apple's iOS Devs forums with no answer, I'm trying to see if anyone's got any experience with such issue.
I'm using xcode for iOS 7.
MapView won't update. I'm quite sure the problem's within the simulator, though I'm not sure how to check it. I'd love to take this project on a real device but my iOS 7 device's still in store.
I created a MKMapView nested under a View (nested under a ViewController) -> Added CoreLocation and MapKit into Frameworks -> Connected the MKMapView to the right property mapView.
My files look like this:
MapScanViewController.h:
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapScanViewController : UIViewController<MKMapViewDelegate>
// I was trying to create a label and print the
// userLocation description into the label - but none worked
#property (nonatomic,retain) IBOutlet UILabel *myLabel;
#property (nonatomic,strong) IBOutlet MKMapView *mapView;
#end
And MapScanViewController.m :
#import "MapScanViewController.h"
#implementation MapScanViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_mapView.delegate = self;
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
[_mapView setRegion:[_mapView regionThatFits:region] animated:YES];
// Label idea did not work eiter
[_myLabel setText:[userLocation description]];
}
#end
When I try to change location to Apple's Infinite loop, the map stays still like nothing's changing at all. Also tried to use bicycle ride and running but nothing happened.
I tried to reset the iOS Simulator few times which did not help at all and of course tried to manually set the location from within xcode it-self.
Tried to add/force this (which did not help either):
if (_mapView.showsUserLocation)
{
_mapView.showsUserLocation = NO;
_mapView.showsUserLocation = YES;
}
None worked for me. MapView just wont respond.
I verified the map view
// Meters-Miles convertion
#define METERS_PER_MILE 1609.344
// Just wanted to check if MapView's dead or not - worked- it took me to see (39.28..., -76.58...)
- (void)viewWillAppear:(BOOL)animated {
// 1
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 39.281516;
zoomLocation.longitude= -76.580806;
// 2
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 0.5*METERS_PER_MILE, 0.5*METERS_PER_MILE);
// 3
[_mapView setRegion:viewRegion animated:YES];
}
you have to call _mapView.showsUserLocation = YES; before you get anything from the map.
That call will for prompt the user for access to location services.
As Daij-Djan said Try like this
- (void)viewDidLoad
{
_mapView.showsUserLocation = YES;
}
Everytime I start the app, the first time seeing the map results in a default map that is always zoomed out with no annotations. When I go back on the navigation controller and go back into the map, it now shows the correct region with the appropriate pins. The code I use to add the
- (void) zoomIn {
mapView.showsUserLocation = YES;
CLLocationCoordinate2D annotation;
annotation.latitude = 47.640071;
annotation.longitude = -122.129598;
MKPointAnnotation *annoPoint = [[MKPointAnnotation alloc] init];
annoPoint.coordinate = annotation;
annoPoint.title = #"name";
[mapView addAnnotation:annoPoint];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(annotation, 500, 500);
[mapView setRegion:region animated:YES];
}
I call this block of code from the viewDidLoad, but it only works after I go back to the main page from the navigation controller and enter this UIViewController again.
Does anyone know what the problem is or have seen it before?
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
// this delegate fonction is called when the userlocation is updated
// try to move your code here
}
you have also
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
}
hope this helps
Show us your viewDidLoad function, you're probably calling zoomIn too early, maybe before your MKMapView has been initialized.