42 votes

Comment effectuer une recherche dans MKMapView avec UISearchBar ?

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

La fonction en question ne devrait pas être difficile à réaliser, 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 puisse m'aider à déplacer la carte et à la centrer à cet endroit.

Je veux dire, que dois-je demander, est-ce que Apple fournit une "méthode API de recherche d'adresse" ? ou dois-je utiliser directement l'API de Google Maps ?

J'aimerais savoir comment procéder.

56voto

user1466453 Points 411

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

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

39voto

Goles Points 5143

Ok, pour répondre à ma propre question :

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

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

1) Téléchargez un framework/une 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, et plusieurs applications commerciales semblent l'utiliser. Alors ajoutez-le à votre projet ( instructions aquí ).

2) Pour demander une adresse à Google Maps, nous devons construire une URL de requête comme ceci : 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 de la barre de 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];
}

Nous devons bien sûr ensuite traiter la réponse du serveur GoogleMaps ( Note : beaucoup de validations manquent)

//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 pour zoomer ma carte, ce qui devrait être maintenant une chose triviale.

- (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 aidera quelqu'un, car la partie JSON a été très difficile à comprendre, la bibliothèque n'est pas très bien documentée à mon avis, mais elle est quand même très bonne.

EDIT :

J'ai modifié le nom d'une méthode en "searchCoordinatesForAddress :" en raison de la question de @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 ajouter un objet NSMutableData pour contenir toutes les requêtes au serveur de Google. ( rappelez-vous que les requêtes HTTP sont faites par morceaux. )

2voto

tjv Points 652

Si quelqu'un d'autre a le même problème, voici le lien : https://github.com/stig/json-framework/ défilement vers le bas jusqu'à Le projet a été renommé SBJson

Voici également le code permettant de récupérer toutes les données avant que votre application ne les utilise. Notez que la méthode du délégué "a reçu les données" car elle ajoute les données téléchargées à l'objet de données mutables.

J'ai simplement utilisé la méthode de recherche de M. GANDOS, telle qu'elle est, car elle fonctionne bien.

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

// STEP ONE // CETTE ÉTAPE EST IMPORTANTE CAR ELLE CRÉE L'OBJET DE DONNÉES MUTABLES DÈS QU'UNE RÉPONSE EST REÇUE.

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

}

/// ÉTAPE DEUX // CETTE ÉTAPE EST IMPORTANTE CAR ELLE AJOUTE L'OBJET DE DONNÉES AUX DONNÉES.

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

// ÉTAPE TROIS...... // MAINTENANT QUE VOUS AVEZ TOUTES LES DONNÉES, UTILISEZ-LES.

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

2voto

Vali Points 21

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 voulez rechercher une rue, voici le bon lien.

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

Avis que le 2e ? devrait être & .

1voto

William Denniss Points 3781

Vous pouvez utiliser le service API de Google pour obtenir les coordonnées lat/long à partir d'une chaîne de recherche textuelle. Veillez à transmettre l'emplacement actuel de l'utilisateur afin que les résultats soient pertinents. Lisez les réponses à cette question : Rechercher et afficher les emplacements des entreprises sur MKMapView

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X