Update MKMapView when updating user location or using default values

I try to update my map view and download new data from the server when the device acquires the user's location. That'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 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 connection - (void): (NSURLConnection *) connection didReceiveData: (NSData *) data to create and add annotations.

Here's what happens: sometimes I get the location after a while, so I already downloaded data close to the default location. Then I get the location and it should delete the old annotations and add new ones, instead, I still see the old annotations, and the new ones are added (let me get 10 annotations every time, so that means I have 20 on my map, when I will have 10).

What am I doing wrong?

+6
source share
1 answer

Well, it may be a little long, but it worked for me, and I really hope it helps you. This is from an application that is used to exchange various traffic status reports between drivers.

I also had this problem, I tried to download annotations from the server, and then delete them and reload the annotation array to the card every time the user sends the annotation to the server himself / clicks the "Update" button / every 1.5 minutes so that he always had the current set.

So I thought that this might have something to do with the time interval that is required to download new annotations from the server or with the array itself, later I realized that it could also be related to how all the code was organized and that, perhaps some things just get in the way / others time.

What I did basically moves the [self.map addAnnotations:AN ARRAY OF ANNOTATIONS] to the main thread and the whole loading process back, I also used a temporary array instead of "self.map.annotations" to remove the current annotations, it worked OK, so I just left it like that :), although I am not a world-class expert (even close), and I'm sure that others can have a more professional and effective solution, example code:

 //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 comment on my answer, as I will also be very happy to learn about a less complicated way to resolve this issue.

I think that most of these problems would be resolved if there was a way to โ€œwait for completionโ€ when using background threads, because now it happens that the code continues to work before the whole loading process - the process of creating annotation-loading for creating a map is actually completed.

0
source

Source: https://habr.com/ru/post/887011/


All Articles