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.
精彩评论