MKMapView 重置回世界视图:重新烘焙

Posted

技术标签:

【中文标题】MKMapView 重置回世界视图:重新烘焙【英文标题】:MKMapView reset back to world view: Rebaked 【发布时间】:2013-03-21 21:46:03 【问题描述】:

我的 MKMapView 一直存在内存泄漏问题(已向 Apple 报告,但没有回应),因此作为一种变通方法,我尝试仅分配一个 MKMapView 并重新使用该映射,而不是重新分配一个新映射。我遇到的问题是我还不能将 MKMapView 重置为它开始的视图。我假设因为我在美国工作,我最初得到的看法是这样的:

(来源: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 的按钮时,我得到以下地图(还没有惊喜):

(来源:cprince.com)

然后,当我从该视图导航离开(使用导航控制器)然后重新进入视图(再次调用 viewWillAppear,但这次它重新使用之前分配的 MKMapView)时,我得到以下地图视图:

(来源:cprince.com)

当然,由于 viewWillAppear 的这一部分,我应该得到原始的默认区域:

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

setRegion 是在 addSubview 之后还是之前都没有关系。也就是说,下面的更改并不能纠正问题:

- (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/***/Map.zip 获得)。

想法?

第一次改变

我将 defaultRegion 设为静态而不是实例变量,这并没有显着改变情况。 (我在下面报告了默认区域的纬度/经度)。这是地图中的结果:

(来源: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 的区域设置? 您是否检查了页面首次加载时创建的 defaultRegion 中的值?也许你没有创造你认为的区域。例如,如果它可能因为您不在 (0,0) 处而失败,但给它一个 180x360 的跨度,那么它会进入无效坐标。 将带有动画集的区域设置为 NO 不会改变这种情况。刚刚试过。 如果 (!firstTime),defaultRegion 未初始化。 我只是放了一些调试输出,默认区域是:defaultRegion: center: lat: 30.000000, long: -40.000000;跨度:180.000000 dlat:dlong:360.000000;所以那应该是北纬 30 度和西经 40 度,是的,这确实使我们处于大西洋的中间。所以,问题似乎是由于某种原因我的默认坐标设置不正确。 (这是修复实例变量问题后的情况)。 【参考方案1】:

如果您将视图控制器设置为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,因此请确保nil 地图的delegate(因为旧视图控制器将消失)。如果您想继续将视图控制器的新实例设置为 MKMapViewDelegate,则只需在将地图视图重新添加到详细视图控制器的新实例时再次设置 delegate


旧答案:

当您设置defaultRegion 时,这是一个实例变量。因此,当您关闭视图时,它就会丢失。当您返回地图时(即 firstTimeNO),defaultRegion 从未初始化,因此为 0,0,因此位于大西洋中部。

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

【讨论】:

见上面我的 cmets。是的,这应该有效。但它没有。 @ChrisPrince 好的,您现在(通过将defaultRegion 设为静态)正确保存了defaultRegion。下一个问题是您在创建MKMapView 后立即设置defaultRegion,但设置区域以覆盖美国的过程是异步发生的。请参阅我的更新答案。 @ChrisPrince 我已经添加了保存defaultRegion的代码。 非常好!谢谢!我做了那个改变和另一个改变。我将初始地图创建放入应用程序委托中,因为我第一次创建地图时并不总是使用默认区域。我把更新后的代码放在这里:cprince.com/***/Map2.zip

以上是关于MKMapView 重置回世界视图:重新烘焙的主要内容,如果未能解决你的问题,请参考以下文章

iPhone - MKMapView 实例的问题

MKMapView 如何将经度纬度转换回厘米?

重新进入视图时 iPod 上的 MKMapView 崩溃

SwiftUI:避免使用 MKMapView+UIViewRepresentable 在 TabView 中重新创建/重新渲染视图

我可以重新定位已经放置在 MKMapView 上的 MKAnnotationView 吗?

在 Cocoa macOS 应用程序中,如何获取 MKMapView 左下角的度数坐标?