2

我有一组地址,我需要使用 Google 的 Geocode api 将其转换为 Lat/Long。我将地址和城市输入 Google 地理编码 URL,它形成了正确的连接 URL。

基本上我希望能够使用 for 循环来创建多个 NSURLConnection 请求,返回多个响应。

-(void)setString{
 for (int i = 0; i < [businessArray count]; i ++)
{         
NSString *address = [addressArray objectAtIndex:0];
NSString *city = [locationDict valueForKey:@"city"];
NSString *geocodeURL = [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/geocode/json?address=%@,+%@,&sensor=true", address, city];
    geocodeURL = [geocodeURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:geocodeURL]
                                                           cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                       timeoutInterval:10];
    NSLog(@"%@", request);
    geoCodeConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];


    if (geoCodeConnection)
    {
        responseData = [NSMutableData data];
        connectionIsActive = YES;
        NSLog(@"connection active");

    } else {
        NSLog(@"connection failed");
        connectionIsActive = NO;
    }

}
}

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


    NSString *responseString    = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
    NSError *jsonError          = nil;

    SBJsonParser *json          = [[SBJsonParser alloc] init];

    NSDictionary *parsedJSON    = [json objectWithString:responseString error:&jsonError];

    NSString *lat= [[[[parsedJSON valueForKey:@"results"] valueForKey:@"geometry"] valueForKey:@"location"] valueForKey:@"lat"];
    NSString *lng= [[[[parsedJSON valueForKey:@"results"] valueForKey:@"geometry"] valueForKey:@"location"] valueForKey:@"lng"];

    NSLog(@"lat = %@ long= %@", lat, lng);
    connectionIsActive          = NO;
    [geoCodeLatArray addObject:lat];
    [geoCodeLngArray addObject:lng];
    NSLog(@"geoCodeArrayLat: %@", geoCodeLatArray);


}

现在代码只返回最后一个地址'纬度和经度。如何使用 JSON 发送多个请求并返回多个响应?

4

3 回答 3

1

试试这个我正在使用这个,

for(int i=0;i< businessArray.count;i++)
{
    NSString *address = [addressArray objectAtIndex:i];
    NSString *city = [locationDict valueForKey:@"city"];
    NSString *address = [NSString stringWithFormat:@"%@,%@", address, city];

    CLLocationCoordinate2D location = [self geoCodeUsingAddress:address];
    // then here store the location.latitude in lat array and location.longitude in long array.
}

- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)address
{
    NSString *esc_addr =  [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSString *req = [NSString stringWithFormat:@"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%@", esc_addr];

    NSDictionary *googleResponse = [[NSString stringWithContentsOfURL: [NSURL URLWithString: req] encoding: NSUTF8StringEncoding error: NULL] JSONValue];

    NSDictionary    *resultsDict = [googleResponse valueForKey:  @"results"];
    NSDictionary   *geometryDict = [resultsDict valueForKey: @"geometry"];
    NSDictionary   *locationDict = [geometryDict valueForKey: @"location"];

    NSArray *latArray = [locationDict valueForKey: @"lat"];
    NSString *latString = [latArray lastObject];

    NSArray *lngArray = [locationDict valueForKey: @"lng"];
    NSString *lngString = [lngArray lastObject];

    CLLocationCoordinate2D location;
    location.latitude = [latString doubleValue];
    location.longitude = [lngString doubleValue];

    return location;
}

更新上述函数:

- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)address
{
    double latitude = 0, longitude = 0;
    NSString *esc_addr =  [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSString *req = [NSString stringWithFormat:@"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%@", esc_addr];
    NSString *result = [NSString stringWithContentsOfURL:[NSURL URLWithString:req] encoding:NSUTF8StringEncoding error:NULL];
    if (result) {
        NSScanner *scanner = [NSScanner scannerWithString:result];
        if ([scanner scanUpToString:@"\"lat\" :" intoString:nil] && [scanner scanString:@"\"lat\" :" intoString:nil]) {
            [scanner scanDouble:&latitude];
            if ([scanner scanUpToString:@"\"lng\" :" intoString:nil] && [scanner scanString:@"\"lng\" :" intoString:nil]) {
                [scanner scanDouble:&longitude];
            }
        }
    }
    CLLocationCoordinate2D location;
    location.latitude = latitude;
    location.longitude = longitude;
    return location;
}

这对我有用。

于 2013-07-08T05:52:02.417 回答
1

您可能会使用异步方法来解决问题,该方法执行请求并具有完成块,当结果可用时将调用该完成块。这个完成块提供一个参数结果,它是连接请求的结果。

该方法可以声明如下:

typedef void (^completion_block_t) (id result);

- (void) fetchGeoCoordinateForAddress:(NSString*)address 
                    completionHandler:(completion_block_t)completionHandler;

比如说,如果请求成功,块中的参数结果是响应数据的 JSON 表示。否则,结果是一个指示错误的 NSError 对象。但具体细节取决于您如何实现该方法fetchGeoCoordinateForAddress:completionHandler:

现在您可以按如下方式设置循环:

for (NSString* address in addresses) 
{
    [self fetchGeoCoordinateForAddress:address completionHandler:^(id result) {
        if (![result isKindOfError:[NSError class]]) // check if result is an error
        {
            // Note: result is not nil and is a NSDictionary representation of JSON.

            // Retrieve the "location" from the response:
            NSDictionary* location = result[@"results"][@"geometry"][@"location"];

            // Multiple request can occur at the same time! Thus, we need to 
            // synchronize access to the result array "myLocations" through 
            // accessing it *exclusively and everywhere* on the main thread:
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.myLocations addObject:location];
            });                
        }
        else {
            // got error
            DebugLog(@"ERROR: %@", result);
        }
    }
}

注意:您的实际代码可能会因实际 JSON 和其他详细信息而略有不同。

关于方法的实现,fetchGeoCoordinateForAddress:completionHandler:您有几个选择:

  1. 使用第三方库并实现一个简单的便利包装器fetchGeoCoordinateForAddress:completionHandler:

  2. 创建您自己的“MyHTTPConnectionOperation”类,该类NSURLConnection将响应数据和其他一些有用的状态信息封装在一个专用类中。此类通过start方法异步执行请求,并具有完成处理程序。基本上,所有第三方网络库都会使用这种方法。然后实现包装器。

  3. 如果足够并且在您的上下文中工作,请使用 NSURLConnection 的异步便捷方法。这是实现最快但最不灵活的方法,可能并非在所有情况下都有效,也可能仅在次优情况下有效。

编辑:

一些提示:

  • 如果可能,NSJSONSerialization用于解析 JSON 和创建 Foundation 表示。其他第三方库仅在您有特殊要求时提供轻微优势,例如您需要“使用 NSData 对象进行分块解析”——这在您想要同时下载和解析时很有用。或者您需要创建除 Foundation 之外的其他表示形式 - 例如 C++ 容器,或者您想直接创建具有 SAX 样式解析的模型。或者,您需要更好的性能和更低的内存食物打印,因为您正在接收要保存到磁盘的超大字符串。NSJSONSerialization最近变得相当快,所以今天不应该单独讨论“性能”。

  • 请求的超时时间不应低至 10 秒。在蜂窝连接中,这太少了。将其保留为默认值。

  • 如果您打算实现自己的“HTTPConnectionOperation”类,我在此处的要点上放了一个非常有限的示例,可以让您快速开始。

于 2013-07-08T09:28:28.767 回答
0

我认为你必须从 AFNetworking 开始

AFNetworking1
AFNetworking2

因为 AFNetworking 在调度和排队请求以及暂停和取消请求方面提供了很大的功能和灵活性。

于 2013-07-08T05:51:43.280 回答