更新用户位置或使用默认值时刷新 MKMapView

Posted

技术标签:

【中文标题】更新用户位置或使用默认值时刷新 MKMapView【英文标题】:Refreshing a MKMapView when the user location is updated or using default values 【发布时间】:2011-08-16 02:00:21 【问题描述】:

当设备获取用户位置时,我正在尝试刷新我的地图视图并从服务器加载新数据。 这就是我正在做的事情:

- (void)viewDidLoad 
    CGRect bounds = self.view.bounds;
    mapView = [[MKMapView alloc] initWithFrame:bounds];
    mapView.showsUserLocation=YES;
    mapView.delegate=self;
    [self.view insertSubview:mapView atIndex:0];
    [self refreshMap];


- (void)mapView:(MKMapView *)theMapView didUpdateUserLocation:(MKUserLocation *)userLocation

    //this is to avoid frequent updates, I just need one position and don't need to continuously track the user's location
    if (userLocation.location.horizontalAccuracy > self.myUserLocation.location.horizontalAccuracy) 
        self.myUserLocation = userLocation;
        CLLocationCoordinate2D centerCoord =  userLocation.location.coordinate.latitude, userLocation.location.coordinate.longitude ;
        [theMapView setCenterCoordinate:centerCoord zoomLevel:10 animated:YES];
        [self refreshMap];
    


- (void)refreshMap 
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
    [self.mapView removeAnnotations:self.mapView.annotations];
    //default position
    NSString *lat = @"45.464161";
    NSString *lon = @"9.190336";
    if (self.myUserLocation != nil) 
        lat = [[NSNumber numberWithDouble:myUserLocation.coordinate.latitude] stringValue];
        lon = [[NSNumber numberWithDouble:myUserLocation.coordinate.longitude] stringValue];
    
    NSString *url = [[NSString alloc] initWithFormat:@"http://myserver/geo_search.json?lat=%@&lon=%@", lat, lon];

    NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
    [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
    [url release];
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];

我还有一个 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data,用于创建和添加注释。

会发生以下情况: 有时我会在一段时间后获得位置,所以我已经在默认位置附近加载了数据。 然后我得到了位置,它应该删除旧注释并添加新注释,而不是我一直看到旧注释并且无论如何都会添加新注释(假设我每次收到 10 个注释,所以这意味着我的地图上有 20 个,而我应该有 10 个)。

我做错了什么?

【问题讨论】:

在 refreshMap 中,在 removeAnnotations 行之前,检查 self.mapView 是否为 nil。 不是零,这是我得到的:> 我什至无法正确测试,因为我只在真实设备上而不是在模拟器中注意到这个问题......但代码在逻辑上是否正确? 我没有发现任何明显的问题。也许这与注释的添加方式或在 viewForAnnotation 中的方式有​​关。 这是我在 for 循环中添加注释的方法(相关部分):UserAnnotation *UserAnnotation = [[UserAnnotation alloc] initWithLocation:theCoordinate]; UserAnnotation.title = [single objectForKey:@"address"]; UserAnnotation.userID = [single objectForKey:@"id"]; [self.mapView addAnnotation:UserAnnotation]; 我在这里也看不到任何错误...:/ 【参考方案1】:

好的,这可能有点长,但它对我有用,我真的希望它会对你有所帮助。 这是来自用于在驾驶员之间共享不同交通状态报告的应用程序。

我也遇到了这个问题,我尝试从服务器加载注​​释,然后删除它们并将注释数组重新加载到地图上,每次用户自己向服务器发送注释/按下“刷新”按钮/每 1.5分钟 - 这样他将始终拥有当前设置。

所以我认为这可能与从服务器加载新注释所需的时间间隔有关,或者与数组本身有关,后来我意识到它也可能与整个代码的组织方式有关并且可能有些事情妨碍了其他人的方式/时机。

我所做的基本上是将[self.map addAnnotations:AN ARRAY OF ANNOTATIONS]命令移到主线程并将整个加载过程移到后面,我还使用临时数组而不是“self.map.annotations”来删除当前注释,它起作用了好的,所以我就这样离开了:),虽然我不是世界级的专家(甚至不是很接近),我相信其他人可能有更专业和更有效的解决方案,代码示例:

//this is in viewDidLoad, it kicks off the whole process

    [self performSelectorInBackground:@selector(retrieveAnnotationsDataFromServer) withObject:self];

//this is the method for loading data

    -(void)retrieveAnnotationsDataFromServer
    
        NSAutoreleasePool *pool=[[NSAutoreleasePool alloc]init];
        //code for loading..
        NSURL *URL=[NSURL URLWithString:@"http://YOUR SERVER NAME HERE"];
        NSString *result=[NSString stringWithContentsOfURL:URL encoding:4 error:nil];
        NSLog(@"%@",result);
        NSData *data = [NSData dataWithContentsOfURL:URL];
        NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
        [parser setDelegate:self];
        [parser parse];

    //Inside the parser delegate i take each element of the report and store it in a mutable array so that i could create the annotations later (report title, report description/subtitle, report location longitude and report location latitude)

        [pool drain];
        NSLog(@"retrieveannotatinsdatafromserver pool drained");
    

    //Now, in this case the last thing that will happen before the pool is drained is that the parser`s "didEndDocument" method gonna be called, so this is where I delayed the loading like this:

    - (void)parserDidEndDocument:(NSXMLParser *)parser
    
        NSLog(@"parser - document ended, creating annotationsArray");
        NSLog(@"this is the size of RA Array:%d",[self.recievedTitles count]);
        for (int i=0;i<[self.recievedTitles count];i++)
        
            //RC=recieved coordinate
            //RA=recieved annotation
            CLLocationCoordinate2D RC;
            RC.latitude=[[self.recievedLatitude objectAtIndex:i] doubleValue];
            RC.longitude=[[self.recievedLongitude objectAtIndex:i] doubleValue];
            if([self.recievedTitles objectAtIndex:i]==nil)
                continue;
            Annotation *RA=[[Annotation alloc]initWithCoordinate:RC andTitle:[self.recievedTitles objectAtIndex:i] andSubTitle:[self.recievedSubTitles objectAtIndex:i]];

    //the "self.AnnotationsArray" is an array i use to always hold the most current set retrieved from the server        
    [self.AnnotationsArray addObject:RA];
            [RA autorelease];
            NSLog(@"RA %d inserted",i);
         
        NSLog(@"Data retrieving ended, loading annotations to map");
        [self performSelectorOnMainThread:@selector(addAnnotations) withObject:self waitUntilDone:NO];

    

    //this method was only defined so that i could apply it in the main thread instead of in the background like the whole loading process.. I'm sure it can be done better.

    -(void)addAnnotations
    
        [self.Map addAnnotations:self.AnnotationsArray];
        NSLog(@"annotations loaded to Map");
    

    //now we have retrieved them from the server for the first time, the reloading and refreshing part comes next, this method is called any time the user press refresh, sends a report to the sever, or automatically every 1.5 minutes:

    -(void)refreshMap
    
        NSArray *annotationsToDelete=[[NSArray alloc] initWithArray:self.AnnotationsArray];
        [self.Map removeAnnotations:annotationsToDelete];
        [annotationsToDelete release];
        [self performSelectorInBackground:@selector(retrieveAnnotationsDataFromServer) withObject:self];
    

请对我的回答发表评论,因为我也很乐意学习一种不太复杂的方法来解决这个问题。

我认为如果在使用后台线程时有一种“等到完成”的方法,大多数这类问题都会得到解决,因为现在发生的情况是代码在整个下载过程之前继续向前运行 -解析-创建注释-加载到地图的过程实际上已经完成。

【讨论】:

以上是关于更新用户位置或使用默认值时刷新 MKMapView的主要内容,如果未能解决你的问题,请参考以下文章

MKMapView 用户位置 - 授权

MKMapView 不更新用户位置图像

MKMapView 在 iOS 6 上显示用户位置时崩溃

将 MKMapView 更新为从 CLGeocoder 返回的 CLPlacemark

在 MKMapView Objective c 中手动更改用户的当前位置

根据不同的偏好或排序类型重新加载或刷新 MKMapView