MKMapView重置回世界视图:重新计算

3
我一直在使用MKMapView时遇到内存泄漏的问题(已向苹果报告,但未得到回复),因此我尝试了一个解决方法,即只分配一个MKMapView并重复使用该地图,而不是重新分配一个新的地图。但是,我遇到的问题是我无法将MKMapView重置为其起始视图。我认为这是因为我最初在美国工作,所以我最初看到的视图类似于:map of USA (来源:cprince.com。使用以下代码:
static MKMapView *map = nil;

- (void) showUserLocation {    
    [map setShowsUserLocation:YES];

    CLLocationCoordinate2D coord;

    coord.latitude = 39.0; // changed from original coords
    coord.longitude = -105.0;

    MKCoordinateRegion r = MKCoordinateRegionMakeWithDistance(coord, 1000, 1000);

    [map setRegion:r animated:YES];
}

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if (! map) {
        CGRect r = CGRectMake(20, 50, 196, 75);
        map = [[MKMapView alloc] initWithFrame:r];

        defaultRegion = MKCoordinateRegionMake(map.centerCoordinate, MKCoordinateSpanMake(180, 360));
    } else {
        [map setRegion:defaultRegion animated:YES];
    }

    [self.view addSubview:map];
}

- (IBAction)annotateMap:(id)sender {
    [self showUserLocation];
}

当我点击调用annotateMap的按钮时,我会得到以下地图(目前没有惊喜): map of my home
(来源:cprince.com) 然后,当我从此视图导航离开(使用导航控制器),再次进入视图(viewWillAppear再次被调用,但这次它重新使用先前分配的MKMapView),我会得到以下地图视图: map of ocean
(来源:cprince.com) 当然,由于viewWillAppear的这部分代码,我应该得到原始的默认区域:
        defaultRegion = MKCoordinateRegionMake(map.centerCoordinate, MKCoordinateSpanMake(180, 360));
    } else {
        [map setRegion:defaultRegion animated:YES];
    }

无论是在addSubview之前还是之后进行setRegion都没有关系。也就是说,下面的更改不能解决问题:
- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    BOOL firstTime = NO;
    if (! map) {
        firstTime = YES;
        CGRect r = CGRectMake(20, 50, 196, 75);
        map = [[MKMapView alloc] initWithFrame:r];

        defaultRegion = MKCoordinateRegionMake(map.centerCoordinate, MKCoordinateSpanMake(180, 360));
    }

    [self.view addSubview:map];
    if (! firstTime) {
        [map setRegion:defaultRegion animated:YES];
    }
}

使用MKMapRectWorld也没有帮助:

defaultRegion = MKCoordinateRegionForMapRect(MKMapRectWorld);

问题也不是由于MKMapView中的某种竞态条件引起的。如果我更改按钮的处理程序:
- (IBAction)annotateMap:(id)sender {
    defaultRegion = MKCoordinateRegionMake(map.centerCoordinate, MKCoordinateSpanMake(180, 360));
    [self showUserLocation];
}

当地图停留在美国视图上并且在我点击按钮之前等待,问题仍然存在。

我使用的是iOS 6.1.2和XCode 4.6。

(完整的XCode项目可在http://www.cprince.com/stackoverflow/Map.zip中找到)。

您有什么想法?

第一次更改:

我将defaultRegion从实例变量更改为静态变量,但这并没有显著改变情况。(我在下面报告了默认区域的经纬度)。以下是地图上的结果:

map of ocean
(来源:cprince.com)

为了清晰起见,现在的代码如下:

static MKMapView *map = nil;
static MKCoordinateRegion defaultRegion;

- (void) showUserLocation {    
    [map setShowsUserLocation:YES];

    CLLocationCoordinate2D coord;
    coord.latitude = 39.0; // changed from original
    coord.longitude = -105.0;

    MKCoordinateRegion r = MKCoordinateRegionMakeWithDistance(coord, 1000, 1000);

    [map setRegion:r animated:YES];
}

- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    BOOL firstTime = NO;
    if (! map) {
        firstTime = YES;
        CGRect r = CGRectMake(20, 50, 196, 75);
        map = [[MKMapView alloc] initWithFrame:r];

        defaultRegion = MKCoordinateRegionMake(map.centerCoordinate, MKCoordinateSpanMake(180, 360));

        NSLog(@"defaultRegion: center: lat: %f, long: %f; span: %f dlat: dlong: %f", defaultRegion.center.latitude, defaultRegion.center.longitude, defaultRegion.span.latitudeDelta, defaultRegion.span.longitudeDelta);
        //defaultRegion = MKCoordinateRegionForMapRect(MKMapRectWorld);
    }

    [self.view addSubview:map];
    if (! firstTime) {
        NSLog(@"defaultRegion: center: lat: %f, long: %f; span: %f dlat: dlong: %f", defaultRegion.center.latitude, defaultRegion.center.longitude, defaultRegion.span.latitudeDelta, defaultRegion.span.longitudeDelta);
        [map setRegion:defaultRegion animated:YES];
    }
}

- (IBAction)annotateMap:(id)sender {
    //defaultRegion = MKCoordinateRegionMake(map.centerCoordinate, MKCoordinateSpanMake(180, 360));
    [self showUserLocation];
}

你尝试过将动画属性设置为NO来设置区域吗? - Adis
你检查过页面首次加载时创建的defaultRegion中的值了吗?也许你没有创建你认为的区域。例如,如果它失败了,可能是因为你不在(0,0),但是给它一个180x360的跨度,这样它就会进入无效的坐标。 - Craig
将动画设置为NO并不会改变区域设置。我刚试过了。 - Chris Prince
1
我只是加入了一些调试输出,发现默认区域是:defaultRegion: center: lat: 30.000000, long: -40.000000; span: 180.000000 dlat: dlong: 360.000000; 所以应该是北纬30度,西经40度,确实把我们放在了大西洋的中心。因此,问题似乎是由于某种原因设置了错误的默认坐标。(这是修复实例变量问题后的情况)。 - Chris Prince
好的,关于默认区域值,map.centerCoordinate并不是我所期望的值。这里是它的值:map.centerCoordinate: 纬度:30.000000,经度:-40.000000。对于美国中部,我期望的是类似纬度:40,经度:-100的值。听起来像是苹果的一个bug... - Chris Prince
显示剩余2条评论
1个回答

3
如果您将视图控制器设置为MKMapViewdelegate并实现regionDidChangeAnimated,您会发现当您第一次创建地图视图时,centerCoordinate30,-40,但随后它会被设置为37.178181,-96.054581(至少对于美国用户来说)。您显然不能立即依赖region和/或centerCoordinate。您必须给它一个机会重置其region,这显然是异步发生的。
如果您想在MKMapView首次设置defaultRegion后保存它,请设置MKMapViewdelegate属性,然后实现:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    static BOOL firstTime = YES;
    if (firstTime)
    {
        defaultRegion = mapView.region;
        firstTime = NO;
    }
}

注意,在viewWillDisappear中,由于您已经将地图设置为static,请确保在旧视图控制器消失时将地图的delegate设置为nil。如果您想继续让新的视图控制器实例成为MKMapViewDelegate,则只需在重新添加地图视图到新的详细视图控制器实例时再次设置delegate即可。


旧答案:

当您设置defaultRegion时,那是一个实例变量。因此,在您关闭视图时会丢失该变量。当您再次回到地图时(即firstTimeNO时),defaultRegion从未初始化,因此为0,0,因此位于大西洋中央。

显然您没有保存defaultRegion(通常您需要一个协议将其传递回主视图控制器),这使得应用程序很难知道当您再次选择主视图中的项目时该怎么做。


请查看我上面的评论。是的,这应该可以工作。但它没有。 - Chris Prince
@ChrisPrince 好的,现在你通过将 defaultRegion 设为静态变量来正确保存了 defaultRegion。下一个问题是你在创建 MKMapView 后立即设置了 defaultRegion,但是覆盖美国区域的过程是异步进行的。请参考我的更新答案。 - Rob
@ChrisPrince 我已经添加了保存 defaultRegion 的代码。 - Rob
非常好!谢谢!我做了那个更改和另一个更改。我把初始地图创建放到应用程序委托中,因为我不总是在第一次创建地图时使用默认区域。我已经将更新的代码放在这里:http://www.cprince.com/stackoverflow/Map2.zip - Chris Prince

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接