Prevent MKMapViewDelegate methods from being called on device rotation - ios

I am adding some functionality in
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
and
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
I want this to be called when the map region is changed.
How can i prevent these delegate methods from being called when device changes its orientation?

Add a property BOOL didRotate
Then add something like
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
self.didRotate = YES;
}
and
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated{
if(self.didRotate) return;
}
and
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
if(self.didRotate) {
self.didRotate = NO;
return;
}
}

These delegate methods are called when the frame of the map view changes. The frame can change on rotation because of autolayout constraints or autoresizing masks. So one solution would be to keep the map view frame constant.
You could also try to unset the delegate while the interface orientation is changing.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
_mapView.delegate = nil;
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
_mapView.delegate = self;
}

Related

Calling delegate method from IBAction

I am unable to call
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
On following IBAction
- (IBAction)button:(UIButton *)sender {
}
help me
-(IBAction)button:(UIButton *)sender {
[self mapView:yourMapViewObject didUpdateUserLocation:yourLactionObject];
}
You Can't explicitly call the delegate method of MKMapView.
It will get called when the location of the user gets updated.
Take a look at apple doc here
So, if you want to call the same action for MKMapView delegate and button selector, create new function which is called from
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
and also which is called from your button selector. You shouldn't call MKMapView delegate method.

iOS Google Maps Marker drag event

I am building an iOS application using google maps SDK. I can add some markers on the maps when user does a longPressAtCoordinate. My problem is that when I am trying to drag a marker the diiLongPressAtCoordinate is fired before the didBeginDraggingMarker so a new marker is added also.
-(void)mapView:(GMSMapView *)mapView didBeginDraggingMarker:(GMSMarker *)marker{
NSLog(#"begin dragging marker");
}
- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate (CLLocationCoordinate2D)coordinate{
NSLog(#"did long press at mapview");
//when user didLongPressAtCoordinate I add a new marker on the map.
// I want to prevent the execution of this code before the didBeginDraggingMarker method
}
I solved this problem by creating a boolean property called isDragging and changing it's value depending whether a marker is being dragged.
- (void)mapView:(GMSMapView *)mapView didBeginDraggingMarker:(GMSMarker *)marker
{
self.isDragging = YES;
}
- (void)mapView:(GMSMapView *)mapView didEndDraggingMarker:(GMSMarker *)marker
{
self.isDragging = NO;
}
Then I validate if a marker is being dragged whenever a long press is detected:
- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate
{
if (self.isDragging) {
return;
}
NSLog(#"Long press detected");
}

didUpdateUserLocation not getting called re loading the view

I have a mapViewController (in a Navigation Controller). When I open it for the first time, after viewDidLoad, - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation gets called.
When I go back to the previous viewController and come again to the mapViewController, the didUpdateUserLocation delegate is not being called, hence my annotations are not getting shown.
Please help me in finding the solution to the problem. Thank you.
If you want the map view to continue to track the user’s location and update it periodically, you should set MapView showsUserLocation to YES (the default value is NO).
Try
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
...
[mapView setShowsUserLocation: YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
...
[mapView setShowsUserLocation: NO];
}
Apple Doc: http://developer.apple.com/library/ios/#DOCUMENTATION/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html
Call this method in - view will appear method of same class
[locationManager startUpdatingLocation];

Reliably selecting an annotion in MKMapView on start (in both ios 6 and ios 5.1)?

From a detail view of an event I want to go to a MapViewController, zoom in to the annotation, and open it's callout.
Here is some of the relevant code:
#interface MapViewController : UIViewController<MKMapViewDelegate>
...
- (void) viewWillAppear:(BOOL)animated
{
[self displayAnnotations];
}
- (void) viewDidAppear:(BOOL)animated
{
...
// Zoom in to event
[map setRegion:region animated:YES];
}
- (void) mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
...
regionAnimationEnded = YES;
[self selectAnnotation:a];
...
}
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
...
// check to see if the right view is in the array
...
annotationViewDidAppear = YES;
[self selectAnnotation:a];
...
}
- (void) selectAnnotation:(id<MKAnnotation>)annotation
{
if(annotationViewDidAppear && regionAnimationEnded)
{
if(!openedAnnotationFirstTime)
{
[map selectAnnotation:annotation animated:YES];
openedAnnotationFirstTime = YES;
}
}
}
This works on the ios 6 simulator, but on the ios 5.1 simulator (and on the device) the annotion view isn't visible as it says in the docs:
(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
By the time this method is called, the specified views are already added to the map.
So it depends which finishes first: if the region change animation finishes last and the annotation view has appeared it works, otherwise it doesn't.
Any help would be appreciated.
Your selectAnnotation: method is being called twice. Try calling it only once, in mapView:regionDidChangeAnimated: delegate method.
I ended up using perform selector with delay on the actual [map selectAnnotation:annotation animated:YES];
It's a work-around but seems to work nicely.

Is this a bug with MKMapKitDelegate mapView:didUpdateUserLocation?

I've created a test application with only one view containing an MKMapView and a controller which acts as the MapView's delegate.
When I do a fresh build (removed from the device completely before re-installing) and log the callbacks, I can see that mapView:didUpdateUserLocation is called twice before the user has indicated whether they wish to show their current location or not.
The MKUserLocation objects passed to the callback are invalid:
2012-03-13 08:20:17.518 MapTest[3325:707] Did update user location: 0.000000,0.000000
2012-03-13 08:20:17.581 MapTest[3325:707] Did update user location: 0.000000,0.000000
Is this the expected behaviour for MKMapKit or a bug?
Update
I'm running this on my iPhone 4, not a simulator.
Here's the controller code:
#import "ViewController.h"
#implementation ViewController
#synthesize mapView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.showsUserLocation = YES;
self.mapView.delegate = self;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
-(IBAction)trackButtonTapped:(id)sender
{
self.mapView.showsUserLocation = !self.mapView.showsUserLocation;
}
#pragma mark - MKMapKitDelegate
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(#"Did update user location: %f,%f", userLocation.coordinate.latitude, userLocation.coordinate.longitude);
}
-(void)mapViewWillStartLoadingMap:(MKMapView *)mapView
{
NSLog(#"Will start loading map");
}
-(void)mapViewDidFinishLoadingMap:(MKMapView *)mapView
{
NSLog(#"Did finish loading map");
}
-(void)mapViewWillStartLocatingUser:(MKMapView *)mapView
{
NSLog(#"Will start locating user");
}
-(void)mapViewDidStopLocatingUser:(MKMapView *)mapView
{
NSLog(#"Did stop locating user");
}
-(void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error
{
NSLog(#"Did fail loading map");
}
-(void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error
{
if (error.code == kCLErrorDenied){
NSLog(#"User refused location services");
} else {
NSLog(#"Did fail to locate user with error: %#", error.description);
}
}
#end
My opinion is that it's a bug.
How can the map view say user location has been updated when the user hasn't even granted permission?
The workaround I use is to check if userLocation.location is nil:
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
if (userLocation.location == nil)
return;
//do something with userLocation...
}
instead checking for nil userlocation (where 0,0 coordinates can actually be valid) you should use:
if([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized) {
// do something with the coords
} else {
// the coords are invalid
}
With "self.mapView.showsUserLocation = YES;" in viewDidLoad it will start trying to get the user's location straight away. If you take that out it'll wait until the user has pressed a button.
Maybe this helps someone.
For me the "problem" was that I had set show user's location trough interface builder too. Removing it here and setting it through code made the delegate methods get work as suspected.

Resources