我正在尝试刷新我的地图视图,并在设备获取用户位置时从服务器加载新数据。 这就是我正在做的事情:
- (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)连接:(NSURLConnection *)连接didReceiveData:(NSData *)数据,用于创建和添加注释。
以下是发生的事情: 有时我会在一段时间后得到位置,所以我已经将数据加载到默认位置附近。 然后我得到位置,它应该删除旧注释并添加新注释,而不是我不断看到旧注释和新注释(假设我每次都会收到10个注释,所以这意味着当我应该有10个时,我的地图上有20个。
我做错了什么?
答案 0 :(得分:0)
好的,这可能有点长,但它对我有用,我真的希望它能帮到你。 这是来自用于在驱动程序之间共享不同流量状态报告的应用程序。
我也有这个问题,我试图从服务器加载注释,然后删除它们并在每次用户向服务器发送注释时将注释数组重新加载到地图/按下“刷新”按钮/每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];
}
请对我的回答发表评论,因为我也很乐意学习一种不那么复杂的解决方法。
我认为如果在使用后台线程时有一种“等到完成”的方法,大多数这类问题都会得到解决,因为现在发生的事情是代码在整个下载过程之前继续向前运行 - 解析 - 创建注释加载到地图过程实际上已经完成。