mapView not zooming on second try using didUpdateUserLocation - ios

i am loading a mapviewcontroller when the view map button is pressed from my mainviewcontroller:
- (IBAction)mapButton:(id)sender {
MapKitDisplayViewController *mapKitDisplayView = [[MapKitDisplayViewController alloc] init];
[self presentModalViewController:mapKitDisplayView animated:YES];
[mapKitDisplayView release]; mapKitDisplayView = nil;
}
On startup of this map view this method is called, which correctly zooms to the users location:
- (void)mapView:(MKMapView *)myMapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
myMapView.showsUserLocation = YES;
NSLog(#"didUpdateUserLocation = '%#'", userLocation);
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([userLocation coordinate], 20000, 20000);
[myMapView setRegion:region animated:YES];
}
I have a done button on this screen that dismisses this view:
- (IBAction)mapDoneButton:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
}
At this stage the user is taken back to the main view controller, however when i press the view map button again, the didUpdateUserLocation method is never called! Hence, the map view is zoomed out to the default one and wont zoom in as before.
How can i get it to be called again?
thanks

MKMapView object doesn't trigger an update on user location on its own. You need to activate the search by setting showsUserLocation = YES. This will then fetch the user's location and then the delegate method mapView:didUpdateUserLocation: is called. So set this value to YES on viewWillAppear: and once you've the user location you can set it to NO to stop tracking the user. If you don't do that, it periodically updates the user location and calls the delegate method. Without doing this, user location should be unreliable.

What i do is next:
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
[[NSNotificationCenter defaultCenter] postNotificationName:#"gotUserLocation" object:self];}
then in viewDidLoad check of user location is available. if it is not register view controller as reciever for that notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(zoomToLocation) name:#"gotUserLocation" object:nil];
if user location is available just call zoomToLocation method

Related

MKMapView sometimes zoomz to user location sometimes zooms to middle of nowhere

I am using am mapview and sometimes my map will zoom onto my users location when I open it but sometimes it will zoom to the middle of an ocean. I don't know what is causing this, this is the code I am using for zooming. I don't want the map to track the user but just zoom to their location once they open the map
-(void) viewDidAppear:(BOOL)animated{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.mapView.userLocation.coordinate, 600.0f, 600.0f);
[self.mapView setRegion:region animated:YES];
}
-(void) viewDidLoad{
[super viewDidLoad];
self.mapView.delegate = self;
[self.mapView setShowsUserLocation:YES];
}
I encountered this issue before. It seems that mapView is slow to load and detect user location sometimes, resulting in your code in viewDidAppear being executed before the map view can check user's location. Thus, the spot in the ocean.
It will be better to use mapView's delegate to display user location when it's ready:
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
if(isShowUserLocation)
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 600.0, 600.0);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
isShowUserLocation = NO;
}
}
Set isShowUserLocation = YES in viewDidLoad. This ensures the user location is shown once on entry and also selectively when you need it.
Edit 1:
#implementation MapViewController
{
BOOL isShowUserLocation;
}
-(void) viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
[self.mapView setShowsUserLocation:YES];
isShowUserLocation = YES;
}
Edit 2:
Alternatively, use CLLocationManager - see this post. It allows you stop the updating. Do include CoreLocation.framework. You may need to handle some nitty-gritty issues when interacting CLLocationManager with MapView though.
When you pass 0's for lat and long, you will git a spot in the middle of the ocean south of Ghana in Africa.

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

didUpdateUserLocation not calling with view reloaded

I'm getting an error in my IOS application. I've searched in the google and here, but the specific solution was not found!
I have a viewController called mapView that I use in two moments in my app, this view contains a MKMapView and the code.
In my mapView.h there is:
#property (strong, nonatomic) IBOutlet MKMapView *mapSpot;
And in my mapView.m there is:
- (void)viewDidLoad {
[super viewDidLoad];
[mapSpot setShowsUserLocation:YES];
}
- (void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([userLocation coordinate], 500, 500);
[mapSpot setRegion:region animated:YES];
}
So, in the first moment I load the mapView into other ViewController using:
#property (strong, nonatomic) ViewMap *mapView;
mapView = [[ViewMap alloc] initWithNibName:#"ViewMap" bundle:nil];
[self.view addSubview:[mapView view]];
I unload that ViewController and in another ViewController in other moment I load the MapView again, but in this moment the method: - (void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation not is called.
I verify if the first ViewController was unloaded and that was.
When I load the second ViewController there is a new instace of MapView, but not call the delegate method.
Anyone know something about that?
Thanks
==================================================================================
EDIT AND SOLVED:
the problem is in the way you are adding the view, in this line
[self.view addSubview:[mapView view]];
if you only add the view the controller code is not executed, instead of that you has to present the mapView, for example:
[self presentViewController:mapView animated:YES completion:nil];
The problem above, maybe happen because I'm using simulator to test app, and how the simulator not change the position map not get didUpdateUserLocation:
That's the unique explanation that I could have after the review the code, organize the classes read documentation and get error again.
Now, I'm using CLLocationManager to get position, after getting first time the position I stop it.
In the future I'll implement a system that track the user path, so using CLLocationManager is inevitable.
The mapView.m code after changes:
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
CLLocation *loc = [locations lastObject];
// store the location to use in any moment, it needs to be checked because the first time when get the coordinate not pass infos to load places according the current position
if (!location.latitude) {
location = [loc coordinate];
// set center the map at the current position
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(location, 500, 500);
[mapSpotView setRegion:region animated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:#"loadPlaces" object:nil];
[locationManager stopUpdatingLocation];
}
}
if someone has a better solution, please, post here!
That's it!

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.

MKMapView Zooming In On User's Location Once But Not The Second Time in Tab-Bar App (iOS)

I have an MKMapView as part of a Navigation Controller in a Tab Bar based app.
I click a UIButton on the first View Controller and it pushes to the second View Controller which contains the MKMapView. When the Map View loads, it zooms in on the user's location using:
- (void)mapView:(MKMapView *)theMapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
if ( !initialLocation )
{
self.initialLocation = userLocation.location;
MKCoordinateRegion region;
region.center = theMapView.userLocation.coordinate;
region.span = MKCoordinateSpanMake(2.0, 2.0);
region = [theMapView regionThatFits:region];
[theMapView setRegion:region animated:YES];
}
}
When I hit the back button on the Navigation Controller above the MapView and then click back to the map, it no longer zooms in on the user's current location, but just has the full zoom out default:
Here's a picture of the view the second time.
I figure it would work correctly if I could somehow call the didUpdateUserLocation in the viewDidAppear method but I'm not sure how to pull this off since the didUpdateUserLocation is a delegate method.
Is that the right approach or is there a different approach I should take to do this? Thanks!
P.S. I've seen this question but it's slightly different with it's use of a modal view controller
I would pull all of the zooming code into its own method that can be messaged from -viewDidAppear: and -mapView:didUpdateToUserLocation:.
- (void)zoomToUserLocation:(MKUserLocation *)userLocation
{
if (!userLocation)
return;
MKCoordinateRegion region;
region.center = userLocation.location.coordinate;
region.span = MKCoordinateSpanMake(2.0, 2.0); //Zoom distance
region = [self.mapView regionThatFits:region];
[self.mapView setRegion:region animated:YES];
}
Then in -viewDidAppear:...
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self zoomToUserLocation:self.mapView.userLocation];
}
And in the -mapView:didUpdateToUserLocation: delegate method...
- (void)mapView:(MKMapView *)theMapView didUpdateToUserLocation:(MKUserLocation *)location
{
[self zoomToUserLocation:location];
}

Resources