iphone - 显示 kml 数据?不, map 将转到位置 (0,0)

标签 iphone ios mkmapview nsurlconnection kml

我正在使用这个问题中的代码 NSURLConnection download large file (>40MB)下载 KML 文件并使用 Apple 的 KMLViewer 在我的 MKMap 中加载数据。KML 文件很小 <200KB,所以 KMLViewer 就可以了。问题中提供的代码也应该很好,除了当我单击按钮时(这应该发出 url 的请求,然后将数据加载到 map 中) map 刚好到达位置 0,0,缩放非常大,所以我只能看到一张黑色 map 。出了什么问题?我应该怎么办? 这是代码: (顺便说一句,我有两个连接,因为一个连接使用 JSON 从 UIsearchBar 获取 Google 搜索结果中的位置。)

编辑 1

//In the ViewController.m
-(void) searchCoordinatesForAddress:(NSString *)inAddress //for Google location search
{
NSMutableString *urlString = [NSMutableString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@?output=json",inAddress];

[urlString setString:[urlString stringByReplacingOccurrencesOfString:@" " withString:@"+"]];

NSURL *url = [NSURL URLWithString:urlString];

NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

[connection release];
[request release];
}


-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[webData setLength:0]; //webData in the header file
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if ( connection = theConnection ) //theConnection is created before
{
[webData appendData:data];
}
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

NSDictionary *results = [jsonString JSONValue];

NSArray *placemark = [results objectForKey:@"Placemark"];
NSArray *coordinates = [[placemark objectAtIndex:0] valueForKeyPath:@"Point.coordinates"];

double longitude = [[coordinates objectAtIndex:0] doubleValue];
double latitude = [[coordinates objectAtIndex:1] doubleValue];

NSLog(@"Latitude - Longitude: %f %f", latitude, longitude);

[self zoomMapAndCenterAtLatitude:latitude andLongitude:longitude];

[jsonString release];

}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection {

NSString *fileName = [[[NSURL URLWithString:kmlStr] path] lastPathComponent];
NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *folder = [pathArr objectAtIndex:0];

NSString *filePath = [folder stringByAppendingPathComponent:fileName];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];  

NSError *writeError = nil;

[webData writeToURL: fileURL options:0 error:&writeError];
if( writeError) {
    NSLog(@" Error in writing file %@' : \n %@ ", filePath , writeError );
    return;
}
NSLog(@"%@",fileURL);
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error !" message:@"Error has occured, please verify internet connection.."  delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];

[alert show];
[alert release];
}

-(IBAction)showKmlData:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:@"KMLGenerator" ofType:@"kml"];

kml = [[KMLParser parseKMLAtPath:path] retain];

NSArray *overlays = [kml overlays];
[mapview addOverlays:overlays];

NSArray *annotations = [kml points];
[mapview addAnnotations:annotations];

MKMapRect flyTo = MKMapRectNull;
for (id <MKOverlay> overlay in overlays) {
    if (MKMapRectIsNull(flyTo)) {
        flyTo = [overlay boundingMapRect];
    } else {
        flyTo = MKMapRectUnion(flyTo, [overlay boundingMapRect]);
    }
}

for (id <MKAnnotation> annotation in annotations) {
    MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
    MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
    if (MKMapRectIsNull(flyTo)) {
        flyTo = pointRect;
    } else {
        flyTo = MKMapRectUnion(flyTo, pointRect);
    }
}

mapview.visibleMapRect = flyTo;
}

EDIT 2 我做了修改,现在它哪儿也去不了,它崩溃了,因为它找不到 KMLGenerator.kml 文件(路径)

-(void)showData 
{

NSString *url = /*kmlStr;*/@"http://www.ikub.al/hartav2/handlers/kmlgenerator.ashx?layerid=fc77a5e6-5985-4dd1-9309-f026d7349064&kml=1";
NSURL *path = [NSURL URLWithString:url];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:path];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
theConnection = connection;
[connection release];
[request release];

}

//Search Coordinates for address entered in the searchBar
-(void) searchCoordinatesForAddress:(NSString *)inAddress
{
NSMutableString *urlString = [NSMutableString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@?output=json",inAddress];

[urlString setString:[urlString stringByReplacingOccurrencesOfString:@" " withString:@"+"]];

NSURL *url = [NSURL URLWithString:urlString];

NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

[connection release];
[request release];
}

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webData setLength:0]; //Here i get an alert: NSData may not respond to -setLength
                           //webData is a NSData object.
}


-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [webData appendData:data]; //Here i get an alert: NSData may not respond to -appendData
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
    if ( connection == theConnection ) //"theConnection" is for kml file download
    {
        NSString *fileName = [[[NSURL URLWithString:kmlStr] path] lastPathComponent];
        NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *folder = [pathArr objectAtIndex:0];

        NSString *filePath = [folder stringByAppendingPathComponent:fileName];
        NSURL *fileURL = [NSURL fileURLWithPath:filePath];  

        NSError *writeError = nil;

        [webData writeToURL: fileURL options:0 error:&writeError];

        if( writeError) {
            NSLog(@" Error in writing file %@' : \n %@ ", filePath , writeError );
            return;
        }

        NSLog(@"%@",fileURL);
    }
    else //it's a geocoding result
    {
        NSString *jsonString = [[NSString alloc] initWithData:webData encoding:NSUTF8StringEncoding];

        NSDictionary *results = [jsonString JSONValue];

        //check the Google geocode error code before looking for coordinates...        
        NSDictionary *statusDict = [results objectForKey:@"Status"];
        NSNumber *errorCode = [statusDict objectForKey:@"code"];
        if ([errorCode intValue] == 200)  //200 is "success"
        {
            NSArray *placemark = [results objectForKey:@"Placemark"];
            NSArray *coordinates = [[placemark objectAtIndex:0] valueForKeyPath:@"Point.coordinates"];

            double longitude = [[coordinates objectAtIndex:0] doubleValue];
            double latitude = [[coordinates objectAtIndex:1] doubleValue];

            NSLog(@"Latitude - Longitude: %f %f", latitude, longitude);

            [self zoomMapAndCenterAtLatitude:latitude andLongitude:longitude];
        }
        else
        {
            NSLog(@"geocoding error %@", errorCode);
        }

        [jsonString release];
    }
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error!" message:@"Error has occured, please verify internet connection..." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}


- (IBAction)showKmlData:(id)sender
{

NSString *path = [[NSBundle mainBundle] pathForResource:@"KMLGenerator" ofType:@"kml"];

kml = [[KMLParser parseKMLAtPath:path] retain];

NSArray *annotationsImmut = [kml points];
NSMutableArray *annotations = [annotationsImmut mutableCopy];
//[mapview addAnnotations:annotations];
[self filterAnnotations:annotations];

MKMapRect flyTo = MKMapRectNull;

for (id <MKAnnotation> annotation in annotations) {
    MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
    MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
    if (MKMapRectIsNull(flyTo)) {
        flyTo = pointRect;
    } else {
        flyTo = MKMapRectUnion(flyTo, pointRect);
    }
}

mapview.visibleMapRect = flyTo;
}   

最佳答案

仍然很难查明原因,但您发布的代码存在一些问题。

首先,在didReceiveData中,这一行可能不是你想要的:

if ( connection = theConnection ) //theConnection is created before

单个 = 正在执行赋值而不是相等检查(即 ==)。

然而,解决这个问题并不是解决方案(另一个问题在 connectionDidFinishLoading 中)。

didReceiveData 方法不是处理地理编码 JSON 结果的正确位置。 didReceiveData 方法可以为单个 url 请求调用多次。因此,地理编码结果(就像 kml 文件一样)可能会以多个 block 的形式交付,而这些 block 无法在该方法中单独处理。该方法中的 data 可能是完整结果的部分流,对处理没有意义。您应该只将数据附加到 NSMutableData 对象,或者如对链接问题的回答所建议的那样,将数据写入文件。

数据只能在connectionDidFinishLoading方法中处理/解析。

由于您对 kml 文件下载和地理编码使用相同的连接委托(delegate),因此它们都调用相同的 connectionDidFinishLoading 方法。在该方法中,您不会检查正在调用哪个连接。

本地理编码 url 请求完成并调用 connectionDidFinishLoading 时,该方法获取 webData 中的任何内容(可能是地理编码结果或空数据)并将其写入 kmlStr 文件。这可能是导致 kml 数据显示“无”的原因。

您必须将地理编码结果的处理移动到 connectionDidFinishLoading 并在那里检查哪个连接正在调用它。

例如:

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [webData appendData:data];
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
    if ( connection == theConnection ) //"theConnection" is for kml file download
    {
        NSString *fileName = [[[NSURL URLWithString:kmlStr] path] lastPathComponent];
        NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *folder = [pathArr objectAtIndex:0];

        NSString *filePath = [folder stringByAppendingPathComponent:fileName];
        NSURL *fileURL = [NSURL fileURLWithPath:filePath];  

        NSError *writeError = nil;

        [webData writeToURL: fileURL options:0 error:&writeError];
        if( writeError) {
            NSLog(@" Error in writing file %@' : \n %@ ", filePath , writeError );
            return;
        }
        NSLog(@"%@",fileURL);
    }
    else //it's a geocoding result
    {
        NSString *jsonString = [[NSString alloc] initWithData:webData encoding:NSUTF8StringEncoding];

        NSDictionary *results = [jsonString JSONValue];

        //check the Google geocode error code before looking for coordinates...        
        NSDictionary *statusDict = [results objectForKey:@"Status"];
        NSNumber *errorCode = [statusDict objectForKey:@"code"];
        if ([errorCode intValue] == 200)  //200 is "success"
        {
            NSArray *placemark = [results objectForKey:@"Placemark"];
            NSArray *coordinates = [[placemark objectAtIndex:0] valueForKeyPath:@"Point.coordinates"];

            double longitude = [[coordinates objectAtIndex:0] doubleValue];
            double latitude = [[coordinates objectAtIndex:1] doubleValue];

            NSLog(@"Latitude - Longitude: %f %f", latitude, longitude);

            [self zoomMapAndCenterAtLatitude:latitude andLongitude:longitude];
        }
        else
        {
            NSLog(@"geocoding error %@", errorCode);
        }

        [jsonString release];
    }
}

(最好避免对多个连接使用相同的委托(delegate)。将地理编码移出到另一个具有自己的连接对象和委托(delegate)方法的类会更清晰。顺便说一下,iOS5 内置了地理编码,因此您不需要自己做。请参阅 CLGeocoder 类。)

我添加了对 Google 错误代码的检查。查询的地址可能没有返回任何结果,在这种情况下将没有地标坐标,在这种情况下纬度和经度将设置为零。这是 map 转到 0,0 的另一个可能原因。

您似乎也在使用 deprecated v2 Google geocoder . This is the latest one但除非您需要支持 iOS4 或更早版本,否则您可能希望改用 CLGeocoder

关于iphone - 显示 kml 数据?不, map 将转到位置 (0,0),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7954852/

相关文章:

ios - 实现 didReceiveRemoteNotification 以在推送到来时显示新的 viewController

iphone - 为什么 viewDidLoad 在关闭 UIIMagePickerViewController 后被调用?

ios - 从 super View 中删除 Nib

ios - 如何仅存储没有时区和实际时间的日期

iOS - Twitter 集成 1.1 oauth

ios - MapView 自定义 Pin 图问题

swift - 如何使 map 注释标注在 Swift 中打开一个新的 View Controller ?

iphone - 核心数据。 ExecuteFetchRequest 出现故障 NSManagedObject(不在 RAM 中)

iOS:我从 CLLocationManager 获得的位置与 MKMapView 的 userLocation 属性之间的区别

Objective-C播放声音