Search nearby in iOS Maps - iphone

I am trying to build a simple application using MapKit that will automatically search for a specific place when the app launches and drop pin(s) on the map at the locations(s). I am seeing all sorts of ways to load locations (lat/lon, etc), but nothing that lets me search for a specific business name, restaurant name, etc.
I am expecting to work with Apple Maps. However, if Google Maps would be a better solve than so be it.
Any help would be appreciated. Thanks

iOS >= 6.1 provides MKLocalSearch, MKLocalSearchRequest to search for natural language points of interest. Sample
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.region = regionToSearchIn;
request.naturalLanguageQuery = #"restaurants"; // or business name
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:request];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
// do something with the results / error
}];

i know its late but hope this helps!
[super viewDidLoad];
[self.searchDisplayController setDelegate:self];
[self.ibSearchBar setDelegate:self];
self.ibMapView.delegate=self;
// Zoom the map to current location.
[self.ibMapView setShowsUserLocation:YES];
[self.ibMapView setUserInteractionEnabled:YES];
[self.ibMapView setUserTrackingMode:MKUserTrackingModeFollow];
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate=self;
[locationManager startUpdatingLocation];
[self.ibMapView setRegion:MKCoordinateRegionMake(locationManager.location.coordinate, MKCoordinateSpanMake(0.2, 0.2))];
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.region = self.ibMapView.region;
request.naturalLanguageQuery = #"restaurant";
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
localSearch = [[MKLocalSearch alloc] initWithRequest:request];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
results = response;
if (response.mapItems.count == 0)
NSLog(#"No Matches");
else
for (MKMapItem *item in response.mapItems)
{
NSLog(#"name = %#", item.name);
NSLog(#"Phone = %#", item.phoneNumber);
[_matchingItems addObject:item];
MKPointAnnotation *annotation =
[[MKPointAnnotation alloc]init];
annotation.coordinate = item.placemark.coordinate;
annotation.title = item.name;
[self.ibMapView addAnnotation:annotation];
}
}];
}

Make the following steps to display nearest places.
Using google API find the Nearest Places Google Places API
The google API provide LAt and Long and address Informations.
Then Store the LAt and Long Values to Array then USing this lat and long values you can display Annotations in Apple map (iOS 6+) and Google Map (iOS 5).

Related

Posting current location to rails from iPhone

I am building a rails-backed iphone app that uses AFNetworking to create posts at specific locations. So the post model has lat/lng parameters that should be filled in with the client's current location.
At this point, the posts can be made, but the lat/lng comes up as null.
In my (save:) method I pass a conditional to see if a location was found- this is what is failing i.e. "No Location" is logged.
- (void)save:(id)sender {
[self getLocation];
NSArray *locations;
CLLocation *location = [locations objectAtIndex:0];
Post *post = [[Post alloc] init];
post.content = self.contentTextView.text;
post.photoData = UIImagePNGRepresentation(self.imageView.image);
[self.view endEditing:YES];
ProgressView *progressView = [ProgressView presentInWindow:self.view.window];
if (location) {
[post savePostAtLocation:location withBlock:^(CGFloat progress) {
[progressView setProgress:progress];
} completion:^(BOOL success, NSError *error) {
[progressView dismiss];
if (success) {
[self.navigationController popViewControllerAnimated:YES];
} else {
NSLog(#"ERROR: %#", error);
}
}];
} else {
NSLog(#"No Location");
}
}
I have also attempted to implement a locationManager like so
-(void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
[self getLocation];
}
-(CLLocation *) getLocation{
CLLocationManager * locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 80.0f;
[locationManager startUpdatingLocation];
CLLocation * location = [locationManager location];
return location;
}
I think ideally I would implement the savePostAtlocation in the CLLocationManagerDelegate where I could pass in the locations array like this:
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations objectAtIndex:0 /* firstObject */];
if (location) {
[Post createPostAtLocation:location...
But I want to have the post created onSave so I am trying to identify the location but running into some problems..
How do I properly get the current location and pass it into the dictionary?
Any advice on this would be greatly appreciated. Thanks!
Looking at your code, I think you have a slight misunderstanding about how CLLocationManager is designed to work. It looks like you are trying to call [self getLocation] from inside locationManager:didUpdateLocations. This is not correct. Try something like this, inside your save method that is called when you press your button (I would remove the code that's currently in there while testing):
CLLocationManager * locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
self.locationManager.distanceFilter = 80.0f;
[locationManager startUpdatingLocation];
Then it will start generating location data. When that happens, the phone will automatically call locationManager:didUpdateLocations very rapidly. Then, in locationManager:didUpdateLocations you could use:
CLLocation * location = [manager location];
NSLog(#"%#", location);
To see your location data in the console.
What I have written here should get the phone generating location data for you. What you say about createPostAtLocation: in locationManager:didUpdateLocations is probably the correct way to go. When you get the location data, call [manager stopUpdatingLocation] to make the phone stop, then post the location data you got back to your server.

How to draw routes on maps in ios 6?

I want to show maps & draw routes on maps. My application supports for ios 4 plus. So how should i use maps to work on ios 6 as well as before. Also i want to know sholud i use custom mapview in my app to display maps & routes or should i use
[[UIApplication sharedApplication] openURL:]
I have never user MapKits. So please provide if any tutorial. Also let me know if there are any rd party libraries that can be used.
If you don't want an in-app map. Use the following:
NSString *destinationAddress = #"Amsterdam";
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:destinationAddress completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count] > 0) {
MKPlacemark *placeMark = [[MKPlacemark alloc] initWithPlacemark:[placemarks objectAtIndex:0]];
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:placeMark];
MKMapItem *mapItem2 = [MKMapItem mapItemForCurrentLocation];
NSArray *mapItems = #[mapItem, mapItem2];
NSDictionary *options = #{
MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsMapTypeKey:
[NSNumber numberWithInteger:MKMapTypeStandard],
MKLaunchOptionsShowsTrafficKey:#YES
};
[MKMapItem openMapsWithItems:mapItems launchOptions:options];
} else {
//error nothing found
}
}];
return;
} else {
NSString *sourceAddress = [LocalizedCurrentLocation currentLocationStringForCurrentLanguage];
NSString *urlToOpen = [NSString stringWithFormat:#"http://maps.google.com/maps?saddr=%#&daddr=%#",
[sourceAddress stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[destinationAddress stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlToOpen]];
}
This opens the map application and checks if it is ios5 or ios6.
For ios5 I use the LocalizedCurrentLocation from this post http://www.martip.net/blog/localized-current-location-string-for-iphone-apps
For ios6 I use the CLGeocoder to get the placemark and then open the map with it and the current location.
Remember to add CoreLocation.framework and MapKit.framework
I think this'll help you:
http://developer.decarta.com/Apis/IOS/Tutorial/Lesson6
http://developer.decarta.com/Apis/IOS/Tutorial/Lesson6Example
Or this?
http://spitzkoff.com/craig/?p=136
Maybe this is fun to do if you want data in your map:
http://www.raywenderlich.com/21365/introduction-to-mapkit-in-ios-6-tutorial
Or some basic information about Mapkit
http://www.techotopia.com/index.php/Working_with_Maps_on_the_iPhone_with_MapKit_and_the_MKMapView_Class

iPhone - Google Directions API Response Problems

I am using the Google Directions iOS API. I am getting the data using JSON instead of XML. But I am using AFNetworking to simplify this for me. AFNetworking is available at github. Right now, I am able to display an overlay route from one location to another on an MKMapView. Here is my code:
// AFNETWORKING ==========================================================
AFHTTPClient *_httpClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://maps.googleapis.com/"]];
[_httpClient registerHTTPOperationClass: [AFJSONRequestOperation class]];
[_httpClient setDefaultHeader:#"Accept" value:#"application/json"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", location.coordinate.latitude, location.coordinate.longitude] forKey:#"origin"];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", location2.coordinate.latitude, location2.coordinate.longitude] forKey:#"destination"];
[parameters setObject:#"false" forKey:#"sensor"];
[parameters setObject:#"driving" forKey:#"mode"];
[parameters setObject:#"metric" forKey: #"units"];
NSMutableURLRequest *request = [_httpClient requestWithMethod:#"GET" path: #"maps/api/directions/json" parameters:parameters];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
AFHTTPRequestOperation *operation = [_httpClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSInteger statusCode = operation.response.statusCode;
if (statusCode == 200) {
[self parseResponse:responseObject];
} else {
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { }];
[_httpClient enqueueHTTPRequestOperation:operation];
// ROUTE SETUP AND RESPONSE RECIEVED METHOD ==========================================================
- (void)parseResponse:(NSDictionary *)response {
NSArray *routes = [response objectForKey:#"routes"];
NSDictionary *routePath = [routes lastObject];
if (routePath) {
NSString *overviewPolyline = [[routePath objectForKey: #"overview_polyline"] objectForKey:#"points"];
NSLog(#"Status: %#", [response objectForKey: #"status"]);
NSLog(#"Legs: %#", [routePath objectForKey: #"legs[]"]);
_path = [self decodePolyLine:overviewPolyline];
NSInteger numberOfSteps = _path.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [_path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
}
This is the main code to get the route functioning. And it works well! But now what I want to do is get direction list and complete duration and summary. So I took a deep look at Google Directions API Documentation and it tells me to use its different dictionaries and arrays and objects. But I have had no luck. I get a status of OK. When I log the count of the routes array, its only one object. Then the MOST important, legs[] array is NULL.
NSLog(#"Legs is: %#", [routePath objectForKey: #"legs[]"]);
Output:
Legs is (null)
Legs[] includes everything important like the direction list and duration. Summary is not NULL, it gives the name of one of the streets that the route bypasses. I dont know how that is a summary. Might be because there is only one object in the routes array. waypoint_order and warnings[] are NULL too. bounds and of course overview_polyline are valid, thats how I got the route working.
So whats the problem here? Why are so many of the objects Google Directions API provides NULL when I need them?
Thanks!
Alright, the problem was that the response for directions was taking too long. I expected the legs[] response to instantly deliver along with the overview_polyline. So I just had to wait till the response came in, this gives me an opportunity to insert a buffer UI.

Send user location coordinates to SMS.app as an googleMaps-link

I wanna send my location coordinates as a Google Maps link (http://maps.google.com/?saddr=%1.6f,%1.6f) as an SMS but i just can't get it to work... How should I do so that the GoogleMaps-link varies to my location??
MFMessageComposeViewController *controller = [[[MFMessageComposeViewController alloc] init] autorelease];
controller.body = #"This is my location http://maps.google.com/?saddr=%1.6f,%1.6f";
NSString *googleMaps = [NSString stringWithFormat:#"http://maps.google.com/?saddr=%1.6f,%1.6f", location.latitude, location.longitude];
controller.recipients = [NSArray arrayWithObjects:nil];
controller.messageComposeDelegate = self;
[self presentModalViewController:controller animated:YES];
}
}
Any ideas? Would really appreciate an answer!!!!
Thanks you and happy holidays!
shouldn't you have:
controller.body = [NSString stringWithFormat:#"http://maps.google.com/?saddr=%1.6f,%1.6f", location.latitude, location.longitude];
you're hard coding the body and then creating an unrelated string which is probably properly formatted and never doing anything with it.
you need to do location.coordinate.latitude, location.coordinate.longitude assuming location is a cllocation object.

How to search MKMapView with UISearchBar?

I have an application that needs to have a similar search feature like the Apple "Maps" application (included with iPhone, iPod Touch and iPad).
The feature in question should not be a hard thing to do, but I'm really clueless about how to input a Street Address in the search bar, and then obtaining coordinates for that address or something that can help me to actually move the map and center in that place.
I mean, what do I have to query, does Apple provide an "address searching API method" ? or I need to use the google maps API directly ?
I would love to hear how should it be done.
Ok, to answer my own question:
As was mentioned before, the best thing to do is to use the Google Maps API,
it supports a lot of formats but for several reasons I chose to go with JSON.
So here are the steps to perform a JSON query to Google Maps and obtain the coordinate of the query. Note that not all the correct validations are done, this is only a Proof of concept.
1) Download a JSON framework/library for the iPhone, there are several, I chose to go with this one, it's very good and seems an active project, plus several comercial applications seem to be using it. So add it to your project ( instructions here ).
2) To query Google Maps for an address we need to build a request URL like this:
http://maps.google.com/maps/geo?q=Paris+France
This url, will return a JSON object for the query "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];
}
After we handle the UISearchBar search, we must make the request to 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];
}
We must of course then handle the response of the GoogleMaps server ( Note: a lot of validations missing)
//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];
}
Finally the function to zoom my map, which should by now be a trivial thing.
- (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];
}
Hope this helps someone because the JSON part was a real pain to figure out, the library is not very well documented in my opinion, still it's very good.
EDIT:
Modified one method name to "searchCoordinatesForAddress:" because of #Leo question. I have to say that this method is good as a proof of concept but if you plan to download big JSON files , you will have to append to a NSMutableData object to hold all the query to the google server. ( remember that HTTP queries come by pieces . )
This link helps you if you search a region.
NSMutableString *urlString = [NSMutableString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#?output=json",inAddress];
If you want to search a street this is the corect link
NSMutableString *urlString = [NSMutableString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#&output=json",inAddress];
Notice that the 2nd ? should be &.
Swift version, adapted for 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)
}
}
based on user1466453's answer.
If anyone else is having the same issue, heres the link:
https://github.com/stig/json-framework/
scroll down to Project renamed to SBJson
Also, here is the code for getting all the data before your app uses it. Note the delegate method 'did receive data' as it appends the mutable data object with the downloaded data.
I JUST USED MR GANDOS searchCoodinatesMETHOD AS IT IS AS IT WORKS 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];
}
// STEP ONE
// THIS ONE IS IMPORTANT AS IT CREATES THE MUTABLE DATA OBJECT AS SOON AS A RESPONSE IS RECEIVED
-(void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
{
if (receivedGeoData)
{
[receivedGeoData release];
receivedGeoData = nil;
receivedGeoData = [[NSMutableData alloc] init];
}
else
{
receivedGeoData = [[NSMutableData alloc] init];
}
}
/// STEP TWO
// THIS ONE IS IMPORTANT AS IT APPENDS THE DATA OBJECT WITH THE DATA
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedGeoData appendData:data];
}
// STEP THREE......
// NOW THAT YOU HAVE ALL THE DATA MAKE USE OF IT
- (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
}
You can use Google's API service to get lat/long coords from a textual search string. Be sure to pass the user's current location so the results are relevant. Read the answers to this question: Search and display business locations on MKMapView