web-dev-qa-db-fra.com

Comment rechercher MKMapView avec UISearchBar?

J'ai une application qui doit avoir une fonction de recherche similaire comme l'application Apple "Maps" (incluse avec iPhone, iPod Touch et iPad).

La fonctionnalité en question ne devrait pas être difficile à faire, mais je ne sais vraiment pas comment saisir une adresse dans la barre de recherche, puis obtenir les coordonnées de cette adresse ou quelque chose qui peut m'aider à déplacer la carte et à centre à cet endroit.

Je veux dire, qu'est-ce que je dois interroger, Apple fournit-il une "méthode API de recherche d'adresse"? Ou dois-je utiliser l'API google maps directement?

J'aimerais savoir comment cela devrait être fait.

42
Goles

Ok, pour répondre à ma propre question:

Comme cela a été mentionné précédemment, la meilleure chose à faire est d'utiliser l'API Google Maps, elle prend en charge de nombreux formats, mais pour plusieurs raisons, j'ai choisi d'utiliser JSON.

Voici donc les étapes pour effectuer une requête JSON sur Google Maps et obtenir les coordonnées de la requête. Notez que toutes les validations correctes ne sont pas effectuées, ce n'est qu'une preuve de concept.

1) Téléchargez un framework/bibliothèque JSON pour l'iPhone, il y en a plusieurs, j'ai choisi d'aller avec celui-ci , il est très bon et semble être un projet actif, plus plusieurs applications commerciales semblent l'utiliser. Ajoutez-le donc à votre projet (instructions ici ).

2) Pour interroger Google Maps sur une adresse, nous devons créer une URL de demande comme celle-ci: http://maps.google.com/maps/geo?q=Paris+France

Cette url, renverra un objet JSON pour la requête "Paris + France".

3) Code:

//Method to handle the UISearchBar "Search", 
- (void) searchBarSearchButtonClicked:(UISearchBar *)theSearchBar 
{
    //Perform the JSON query.
    [self searchCoordinatesForAddress:[searchBar text]];

    //Hide the keyboard.
    [searchBar resignFirstResponder];
}

Après avoir traité la recherche UISearchBar, nous devons faire la demande à 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];
}

Il faut bien sûr ensuite gérer la réponse du serveur GoogleMaps (Remarque: il manque beaucoup de validations)

//It's called when the results of [[NSURLConnection alloc] initWithRequest:request delegate:self] come back.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{   
    //The string received from google's servers
    NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    //JSON Framework magic to obtain a dictionary from the jsonString.
    NSDictionary *results = [jsonString JSONValue];

    //Now we need to obtain our coordinates
    NSArray *placemark  = [results objectForKey:@"Placemark"];
    NSArray *coordinates = [[placemark objectAtIndex:0] valueForKeyPath:@"Point.coordinates"];

    //I put my coordinates in my array.
    double longitude = [[coordinates objectAtIndex:0] doubleValue];
    double latitude = [[coordinates objectAtIndex:1] doubleValue];

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

    //I zoom my map to the area in question.
    [self zoomMapAndCenterAtLatitude:latitude andLongitude:longitude];

    [jsonString release];
}

Enfin la fonction de zoomer ma carte, ce qui devrait maintenant être une chose banale.

- (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];
}

J'espère que cela aide quelqu'un parce que la partie JSON a été vraiment difficile à comprendre, la bibliothèque n'est pas très bien documentée à mon avis, c'est quand même très bien.

ÉDITER:

Modification d'un nom de méthode en "searchCoordinatesForAddress:" en raison de la question @Leo. Je dois dire que cette méthode est bonne comme preuve de concept, mais si vous prévoyez de télécharger de gros fichiers JSON, vous devrez l'ajouter à un objet NSMutableData pour conserver toute la requête sur le serveur Google. (rappelez-vous que les requêtes HTTP viennent par morceaux.)

39
Goles

C'est peut-être la méthode la plus simple. Il utilise des serveurs Apple pour le géocodage. Parfois, les serveurs Apple fournissent une meilleure réponse que google. Et bientôt (dans IOS 6.1 ), les cartes Google seront complètement hors IOS. Il est donc bon que l'application reste dans les fonctionnalités fournies par les pommes.

-(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];
    }];
}
56
user1466453

Version Swift, adaptée pour 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)
    }
}

basé sur la réponse de user1466453.

2
Eric

Ce lien vous aide si vous recherchez une région.

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

Si vous souhaitez rechercher une rue, c'est le lien correct

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

Remarquez que le 2ème ? devrait être &.

2
Vali

Si quelqu'un d'autre rencontre le même problème, voici le lien: https://github.com/stig/json-framework/ faites défiler vers le bas pour Projet renommé SBJson

En outre, voici le code pour obtenir toutes les données avant que votre application ne les utilise. Notez que la méthode déléguée "a reçu des données" car elle ajoute l'objet de données mutable aux données téléchargées.

JE N'AI UTILISÉ QUE MR GANDOS searchCoodinatesMETHOD AS IT IS AS IT WORKS Well Well

- (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];
}

// PREMIÈRE ÉTAPE // CECI IS IMPORTANT COMME IL CRÉE L'OBJET DE DONNÉES MUTABLE DÈS QUE RÉPONSE IS REÇU)

-(void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
{
    if (receivedGeoData) 
    {
        [receivedGeoData release];
        receivedGeoData = nil;
        receivedGeoData = [[NSMutableData alloc] init];
    }
    else
    {
        receivedGeoData = [[NSMutableData alloc] init];
    }

}

/// DEUXIÈME ÉTAPE // CECI IS IMPORTANT COMME IL AJOUTE L'OBJET DE DONNÉES AUX DONNÉES

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

// TROISIÈME ÉTAPE ...... // MAINTENANT QUE VOUS DISPOSEZ DE TOUTES LES DONNÉES

- (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
}
2
timv

Vous pouvez utiliser le service API de Google pour obtenir des accords lat/long à partir d'une chaîne de recherche textuelle. Assurez-vous de transmettre l'emplacement actuel de l'utilisateur pour que les résultats soient pertinents. Lisez les réponses à cette question: Recherchez et affichez des emplacements commerciaux sur MKMapView

1
William Denniss