MKMapView show incorrectly saved region

2019-01-09 11:55发布

I'm saving map region into user defaults when my iPhone app is closing like this:

MKCoordinateRegion region = mapView.region;
[[NSUserDefaults standardUserDefaults] setDouble:region.center.latitude forKey:@"map.location.center.latitude"];
[[NSUserDefaults standardUserDefaults] setDouble:region.center.longitude forKey:@"map.location.center.longitude"];
[[NSUserDefaults standardUserDefaults] setDouble:region.span.latitudeDelta forKey:@"map.location.span.latitude"];
[[NSUserDefaults standardUserDefaults] setDouble:region.span.longitudeDelta forKey:@"map.location.span.longitude"];

When app launches again, Ш read those values back the same way, so that the user can see exactly the same map view as it was last time:

MKCoordinateRegion region;

region.center.latitude  = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.latitude"];
region.center.longitude = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.longitude"];
region.span.latitudeDelta  = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.latitude"];
region.span.longitudeDelta = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.longitude"];

NSLog([NSString stringWithFormat:@"Region read  : %f %f %f %f", region.center.latitude, region.center.longitude, region.span.latitudeDelta, region.span.longitudeDelta]);

[mapView setRegion:region];

NSLog([NSString stringWithFormat:@"Region on map: %f %f %f %f", mapView.region.center.latitude, mapView.region.center.longitude, mapView.region.span.latitudeDelta, mapView.region.span.longitudeDelta]);

The region I read from user defaults is (not surprisingly) exactly the same as when it was saved. Notice that what is saved comes directly from the map, so it's not transformed in any way. I set it back on map with setRegion: method, but then it is different!

Example results:

Region read  : 50.241110 8.891555 0.035683 0.042915<br>
Region on map: 50.241057 8.891544 0.050499 0.054932

Does anybody know why this happens?

9条回答
够拽才男人
2楼-- · 2019-01-09 12:34

Try also to store attitude like

self.lastCameraAtitude = self.mapView.camera.altitude;

and when u configure your map

[self.mapView.camera setAltitude:self.lastCameraAtitude];

This will set for same region same camera. In your case u only set region but not the camera.

查看更多
冷血范
3楼-- · 2019-01-09 12:36

I can't verify that this works. Can anyone else do so? I'd be willing to bet that what you're seeing is the effect of truncation of your doubles into floats. In some instances, when this happens to me, I've found I can multiply the span by 0.9999 and reset the region, and then it'll be what I want. But not all regions - sometimes it's very different, up to 20% different, especially for small spans.

查看更多
霸刀☆藐视天下
4楼-- · 2019-01-09 12:37

Recently I hit the same thing. Using the insights from earlier answers, the following swift 4 implementation works for me:

override func viewWillAppear(_ animated: Bool) {
    if isMovingToParentViewController {
        setInitialRegion()
        DispatchQueue.main.asyncAfter(deadline: .now(), execute: {
            self.setInitialRegion()
        })
    }
}

This sets an initial zoom region when the map view controller is pushed into view. The synchronous call to setInitialRegion will set a region snapped to a zoom level. The asynchronous call to setInitialRegion will set the exact region. The synchronous call is still needed to remove zoom artifacts.

查看更多
甜甜的少女心
5楼-- · 2019-01-09 12:42

I've found greater success using a multiplication factor of 0.9 instead of 0.999 it still sometimes pushes out but seems to hug closer to the desired zoom. Would still love to solve this issue just to say i beat it! haha

查看更多
【Aperson】
6楼-- · 2019-01-09 12:43

I had the same problem. This is very frustrating. It seems that the documentation for MKMapView is incorrect in some areas regarding datatypes.

If you set the region parameters as (double)s you'll get the error you're having. However if the region parameters are passed (float)s you'll get the correct behavior.

So try

MKCoordinateRegion region = {{0.0f,0.0f},{0.0f,0.0f}};

region.center.latitude = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.latitude"];
region.center.longitude = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.longitude"];
region.span.latitudeDelta = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.latitude"];
region.span.longitudeDelta = (float) [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.longitude"];

mapView.region = region;
查看更多
来,给爷笑一个
7楼-- · 2019-01-09 12:44

If you set up the MapView in InterfaceBuilder, make sure you don't do this:

_mapView = [[MKMapView alloc] init];

As soon as I removed this init line, my map view suddenly began responding properly to all the updates I sent it. I suspect that what happens is that if you do the alloc init, it's actually creating another view that's not being shown anywhere. The one you see on the screen is the one initialized by your nib. But if you alloc init a new one, then that's something somewhere else and it's not going to do anything.

查看更多
登录 后发表回答