Iphone 如何使用UISearchBar搜索MKMapView?

Iphone 如何使用UISearchBar搜索MKMapView?,iphone,ios,cocoa-touch,mkmapview,mkreversegeocoder,Iphone,Ios,Cocoa Touch,Mkmapview,Mkreversegeocoder,我有一个应用程序需要有类似的搜索功能,比如苹果的“地图”应用程序(包括iPhone、iPod Touch和iPad) 这个功能应该不难实现,但我真的不知道如何在搜索栏中输入一个街道地址,然后获取该地址的坐标,或者其他可以帮助我实际移动地图和中心的东西 我的意思是,我要问什么,苹果是否提供了“地址搜索API方法”?或者我需要直接使用谷歌地图API 我很想知道应该怎么做。您可以使用谷歌的API服务从文本搜索字符串中获取lat/long坐标。确保传递用户的当前位置,以便结果相关。阅读此问题的答案:好的

我有一个应用程序需要有类似的搜索功能,比如苹果的“地图”应用程序(包括iPhone、iPod Touch和iPad)

这个功能应该不难实现,但我真的不知道如何在搜索栏中输入一个街道地址,然后获取该地址的坐标,或者其他可以帮助我实际移动地图和中心的东西

我的意思是,我要问什么,苹果是否提供了“地址搜索API方法”?或者我需要直接使用谷歌地图API


我很想知道应该怎么做。

您可以使用谷歌的API服务从文本搜索字符串中获取lat/long坐标。确保传递用户的当前位置,以便结果相关。阅读此问题的答案:

好的,回答我自己的问题:

如前所述,最好的做法是使用谷歌地图API, 它支持很多格式,但出于几个原因,我选择使用JSON

下面是对GoogleMaps执行JSON查询并获取查询坐标的步骤。请注意,并不是所有正确的验证都完成了,这只是一个概念证明

1) 下载一个适用于iPhone的JSON框架/库,我选择了几个,它非常好,似乎是一个活跃的项目,加上几个商业应用程序似乎正在使用它。因此,将其添加到您的项目中(说明)

2) 要查询Google Maps的地址,我们需要构建如下请求URL:

此url将为查询“Paris+France”返回一个JSON对象

3) 代码:

在处理UISearchBar搜索后,我们必须向Google Maps发出请求:

- (void) searchCoordinatesForAddress:(NSString *)inAddress
{
    //Build the string to Query Google Maps.
    NSMutableString *urlString = [NSMutableString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@?output=json",inAddress];

    //Replace Spaces with a '+' character.
    [urlString setString:[urlString stringByReplacingOccurrencesOfString:@" " withString:@"+"]];

    //Create NSURL string from a formate URL string.
    NSURL *url = [NSURL URLWithString:urlString];

    //Setup and start an async download.
    //Note that we should test for reachability!.
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

    [connection release];
    [request release];
}
当然,我们必须处理GoogleMaps服务器的响应(注意:缺少很多验证)

最后是缩放地图的功能,这应该是一件小事了

- (void) zoomMapAndCenterAtLatitude:(double) latitude andLongitude:(double) longitude
{
    MKCoordinateRegion region;
    region.center.latitude  = latitude;
    region.center.longitude = longitude;

    //Set Zoom level using Span
    MKCoordinateSpan span;
    span.latitudeDelta  = .005;
    span.longitudeDelta = .005;
    region.span = span;

    //Move the map and zoom
    [mapView setRegion:region animated:YES];
}
希望这能帮助一些人,因为JSON部分真的很难理解,在我看来,这个库没有很好的文档记录,但它仍然很好

编辑:


由于@Leo问题,将一个方法名称修改为“SearchCoordinates ForAddress:”。我不得不说,这种方法很好地证明了概念,但如果您计划下载大型JSON文件,则必须附加到NSMutableData对象,以将所有查询保存到google服务器。(请记住,HTTP查询是分块进行的。)

如果其他人也有同样的问题,请点击以下链接: 向下滚动至重命名为SBJson的项目

此外,以下是在应用程序使用之前获取所有数据的代码。请注意,委托方法“did receive data”将下载的数据附加到可变数据对象中

我只是用了GANDOS先生的搜索协调方法

- (void) searchCoordinatesForAddress:(NSString *)inAddress
{
    //Build the string to Query Google Maps.
    NSMutableString *urlString = [NSMutableString stringWithFormat:@"http://maps.googleapis.com/maps/api/geocode/json?address=%@&sensor=false",inAddress];

    //Replace Spaces with a '+' character.
    [urlString setString:[urlString stringByReplacingOccurrencesOfString:@" " withString:@"+"]];

    //Create NSURL string from a formate URL string.
    NSURL *url = [NSURL URLWithString:urlString];

    //Setup and start an async download.
    //Note that we should test for reachability!.
    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
{
    if (receivedGeoData) 
    {
        [receivedGeoData release];
        receivedGeoData = nil;
        receivedGeoData = [[NSMutableData alloc] init];
    }
    else
    {
        receivedGeoData = [[NSMutableData alloc] init];
    }

}
///第二步 //这一点很重要,因为它将数据附加到数据对象

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{   
    [receivedGeoData appendData:data]; 
}
//第三步。。。。。。 //既然你有了所有的数据,那就利用它吧

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSString *jsonResult = [[NSString alloc] initWithData:receivedGeoData encoding:NSUTF8StringEncoding];
    NSError *theError = NULL;
    dictionary = [NSMutableDictionary dictionaryWithJSONString:jsonResult error:&theError];

    NSLog(@"%@",dictionary);

    int numberOfSites = [[dictionary objectForKey:@"results"] count];
    NSLog(@"count is %d ",numberOfSites);      
}

-(void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
{
    // Handle the error properly
}

如果搜索区域,此链接将帮助您

NSMutableString *urlString = [NSMutableString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@?output=json",inAddress];
如果你想搜索一条街道,这是corect链接

NSMutableString *urlString = [NSMutableString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=json",inAddress];

注意第二个
应该是
&
这可能是最简单的方法。它使用苹果服务器进行地理编码。有时,苹果服务器比谷歌提供更好的响应。不久(在IOS 6.1中),谷歌地图将完全退出IOS。因此,如果应用程序保留在苹果提供的功能中,那就好了

-(void)searchBarSearchButtonClicked:(UISearchBar *)theSearchBar
{
    [theSearchBar resignFirstResponder];
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder geocodeAddressString:theSearchBar.text completionHandler:^(NSArray *placemarks, NSError *error) {
        //Error checking

        CLPlacemark *placemark = [placemarks objectAtIndex:0];
        MKCoordinateRegion region;
        region.center.latitude = placemark.region.center.latitude;
        region.center.longitude = placemark.region.center.longitude;
        MKCoordinateSpan span;
        double radius = placemark.region.radius / 1000; // convert to km

        NSLog(@"[searchBarSearchButtonClicked] Radius is %f", radius);
        span.latitudeDelta = radius / 112.0;

        region.span = span;

        [theMapView setRegion:region animated:YES];
    }];
}

Swift版本,适用于iOS 9:

let geocoder = CLGeocoder()
geocoder.geocodeAddressString(addressString) { (placemarks, error) in

    if let center = (placemarks?.first?.region as? CLCircularRegion)?.center {

        let region = MKCoordinateRegion(center: center, span: MKCoordinateSpanMake(0.02, 0.02))
        self.mapView.setRegion(region, animated: true)
    }
}

基于user1466453的答案。

您好,但是如果我正确阅读了您的代码,您无法解决给定地址上有多个结果的情况。是的,考虑到此解决方案,解决这一问题应该不难。我是否可以建议使用stringByAddingPercentEscapesUsingEncoding:method而不是用“+”替换空白:)建议:使用
http://maps.google.com/maps/geo?q=%@&output=csv
(以csv模式输出),以避免解析JSON。(无需依赖JSON框架)从技术上讲,对于iOS 5+而言,JSON解析是Cocoa Touch的一部分:)因此也没那么糟糕。请注意,CLGeocoder仍处于初级阶段,在撰写本文时似乎没有返回多个
placemark
值。所有的事情都是一样的,尽管它看起来会在未来取代Google Maps API选项。这个解决方案在iphone 6.0上运行得很好,但是我在iphone 5.0和5.1上遇到了setRegion方法的问题。我收到以下异常:“NSInvalidArgumentException”,原因:“无效区域”。此问题的解决方案是在设置区域属性后添加以下行:区域=[theMapView RegionAtFits:region];FWIW位置标记可能未设置区域,因此上面的代码可能会崩溃。如果placemark.region为零,只需使用另一个半径(比如500米)。除此之外,答案是肯定的。这个答案使用了一些在Swift中不允许访问的不推荐的属性。有人有最新的方法吗?我花了一些时间才发现这两个字符串之间的区别,但是“&”而不是“?”非常有用,谢谢!
-(void)searchBarSearchButtonClicked:(UISearchBar *)theSearchBar
{
    [theSearchBar resignFirstResponder];
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder geocodeAddressString:theSearchBar.text completionHandler:^(NSArray *placemarks, NSError *error) {
        //Error checking

        CLPlacemark *placemark = [placemarks objectAtIndex:0];
        MKCoordinateRegion region;
        region.center.latitude = placemark.region.center.latitude;
        region.center.longitude = placemark.region.center.longitude;
        MKCoordinateSpan span;
        double radius = placemark.region.radius / 1000; // convert to km

        NSLog(@"[searchBarSearchButtonClicked] Radius is %f", radius);
        span.latitudeDelta = radius / 112.0;

        region.span = span;

        [theMapView setRegion:region animated:YES];
    }];
}
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(addressString) { (placemarks, error) in

    if let center = (placemarks?.first?.region as? CLCircularRegion)?.center {

        let region = MKCoordinateRegion(center: center, span: MKCoordinateSpanMake(0.02, 0.02))
        self.mapView.setRegion(region, animated: true)
    }
}