开发者

Refreshing a MKMapView when the user location is updated or using default values

开发者 https://www.devze.com 2023-03-02 11:05 出处:网络
I\'m trying to refresh my map view and load new data from the server when the device acquires the user location.

I'm trying to refresh my map view and load new data from the server when the device acquires the user location. Here's what I'm doing:

- (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];
}

I also have a - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data, to create and add开发者_运维技巧 the annotations.

Here's what happens: sometimes I get the location after a while, so I already loaded data close to the default location. Then I get the location and it should remove the old annotations and add the new ones, instead I keep seeing the old annotations and the new ones are added anyway (let's say I receive 10 annotations each time, so it means that I have 20 on my map when I should have 10).

What am I doing wrong?


Ok this might be a little long but it worked for me and I really do hope it will help you. This is from an app that is used to share different traffic status reports between drivers.

I had this problem also, I tried to load annotations from a server, then delete them and reload the annotations array to the map every time the user sends an annotation to the server himself/presses the "refresh" button/every 1.5 minutes - so that he will always have the current set.

So I thought it might have something to do with the time interval that it takes to load the new annotations from the server, or with the array itself, later I realized it might also be connected to the way the entire code was organized and that maybe some things just got in the way/timing of others.

What I did is basically moving the [self.map addAnnotations:AN ARRAY OF ANNOTATIONS] command to the main thread and the whole loading process to the back, I also used a temp array instead of "self.map.annotations" to delete the current annotations, it worked ok afterwards so I just left it like that :), though I'm not a world-class expert (not even close) and I'm sure others might have a more professional and efficient solution, code sample:

//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];
    }

Please do comment on my answer since I will also be very happy to learn a less complicated way of solving this matter.

I think most of these type of problems would have been solved if there was a way to "wait until done" when using background threads, because now what happens is that the code continues to run forward before the whole process of downloading-parsing-creating annotation-loading to map process is actually finished.

0

精彩评论

暂无评论...
验证码 换一张
取 消