23

This code sets a default zoom level centered around a specified location in viewDidLoad. The code works fine in previous versions of iOS:

CLLocationDistance visibleDistance = 100000; // 100 kilometers
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(location, visibleDistance, visibleDistance);
MKCoordinateRegion adjustedRegion = [mapView regionThatFits:region];
.
.
.
[mapView setRegion:adjustedRegion animated:NO];

However, in iOS6 for locations with latitude above ~ 75 (>75.1) the app crashes with the following message:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:
'Invalid Region <center:nan, nan span:nan, nan>'

I found that for the given zoom level mapView can't set a proper MKCoordinateRegion internally. [mapView regionThatFits:region] returns all values as nan. If I use the region variable directly, it just shows the default map (the whole world).

After some testing I found that by adjusting the visibleDistance I can get the code to work properly. The magic distance seems to be slightly above 20 kilometers (somewhere between 22 and 23 km for a series of latitudes and latitudeDelta values). This happens only on northern latitudes (-80 works just fine).

The maps work at any location after the initial positioning. It looks like Apple changed the way visible map regions are initialized. I'm using a higher zoom level for the affected region as a workaround. Is there any other way to make it work properly?

sbonami
  • 1,723
  • 16
  • 29
Neur0mans3r
  • 231
  • 2
  • 3
  • 3
    Try not to use regionThatFits to generate a MKCoordinateRegion. In iOS 6, I notice that it doesn't work as expected (I think this is a bug). Instead, create MKCoordinateSpan to create a MKCoordinateRegion. Then setup the map view's region to that. Finally use setCenterCoordinate to setup the map view's center position. – Wayne Liu Sep 26 '12 at 17:46
  • But I need to know the `MKCoordinateRegion` that will be shown on the screen to set up additional parameters that control partial loading of locations. Also, if I use a `MKCoordinateSpan` I would show variable default levels of zoom depending on the latitude (unless I compensate manually). `MKCoordinateRegionMakeWithDistance()` works as it should, but the problem is in the method that initializes `mapView` with the region, because the problem is apparent when I use `setRegion:` directly (without `regionThatFits:`) (the map shows the entire world). – Neur0mans3r Sep 27 '12 at 12:51
  • 3
    I was having this problem. When I po'd my mapView, it's frame was 0,0,0,0. Not sure if this was the problem. I removed the `regionThatFits` call in my code, and instead send a region built with `MKCoordinateRegionMake(location, span)` and it seems to be working for me now. – Michael Kernahan Oct 19 '12 at 15:51
  • Neur0mans3r, how do I use MKCoordinateSpan to create the MKCoordinateRegion? – marciokoko Dec 12 '12 at 03:35

4 Answers4

5
CLLocationDistance visibleDistance = 100000; // 100 kilometers
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(location, visibleDistance, visibleDistance);
MKCoordinateRegion adjustedRegion = [mapView regionThatFits:region];
.
.
.
[mapView setRegion:adjustedRegion animated:NO];

It will work..

kleopatra
  • 49,346
  • 26
  • 88
  • 189
  • I did this with my app which is centered at lat15 and long-88 and originally had 4000 meters spam for each. After changing to your suggested 100k it still crashes. It crashes at 10,100, 1000 all the way up to 1billion! :( – marciokoko Dec 10 '12 at 21:00
  • 1
    Using animated:NO is important. With animation:YES the code seems to randomly work/not work, but with NO it works reliably. – Tim T Jan 06 '13 at 21:35
5
CLLocationCoordinate2D southwest, northeast;
southwest.latitude = 34.172684;
southwest.longitude = -118.604794;
northeast.latitude = 34.236144;
northeast.longitude = -118.500938;
BSForwardGeocoderCoordinateBounds *bounds = [BSForwardGeocoderCoordinateBounds boundsWithSouthWest:southwest northEast:northeast];

try this....

Maulik Vekariya
  • 544
  • 7
  • 19
4

I was having crashes with my iPhone4S and console revealed nan values for region. After trying about 7 different solutions from SO and various suggestions from Apple DTS, I solved it by eliminating the regionThatFits call. I simply used:

CLLocationDistance visibleDistance = 100000; // 100 kilometers
MKCoordinateRegion adjustedRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, visibleDistance, visibleDistance);

[_mapView setRegion:adjustedRegion animated:YES];

Apparently there is a problem with that regionThatFits method.

marciokoko
  • 4,952
  • 7
  • 46
  • 90
  • 2
    This works but removes some functionality that is gained by using regionThatFits that is lost by removing it. Your coordinate you'd hoped to center on may be off-screen for example. – avance Jul 03 '13 at 22:26
1

I found a version of this code on a Chinese website and it seems to work for me. He is only bypassing sizeThatFits when the NAN is returned, thus only adjusting if necessary, and if this bug gets fixed by Apple (assuming it is a bug) then it won't be an issue at all.

MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(coordinate, mapSizeMeters, mapSizeMeters);

MKCoordinateRegion adjustedRegion = [mapView regionThatFits:viewRegion];

if (isnan(adjustedRegion.center.latitude)) {
    // iOS 6 will result in nan. 2012-10-15
    adjustedRegion.center.latitude = viewRegion.center.latitude;
    adjustedRegion.center.longitude = viewRegion.center.longitude;
    adjustedRegion.span.latitudeDelta = 0;
    adjustedRegion.span.longitudeDelta = 0;
}


[mapView setRegion:adjustedRegion animated:YES];
avance
  • 1,971
  • 2
  • 21
  • 23