I'm searching for places (would like to only show businesses if possible) like this:
CLLocationCoordinate2D currentCenter = CLLocationCoordinate2DMake(self.locationManager.location.coordinate.latitude, self.locationManager.location.coordinate.longitude);
MKCoordinateRegion currentRegion = MKCoordinateRegionMakeWithDistance(currentCenter, 15000, 15000);
MKLocalSearchRequest *localSearchRequest = [[MKLocalSearchRequest alloc] init];
localSearchRequest.naturalLanguageQuery = identifier;
[localSearchRequest setRegion:currentRegion];
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:localSearchRequest];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *respone, NSError *error) {
if (!error)
{
// Result handling
}
}];
but the results include results from other countries, why is this? I only call this method if the CLLocationManager coordinate passes this check:
CLLocationCoordinate2DIsValid
Thanks!
Related
I am developing an iOS app where I have to get directions from one location to another. I am getting the directions using the MKDirectionsRequest API. This api gives direction between two locations. But the problem is that the route returned by this api do not consider the direction (course) in which the vehicle is moving. Is there any way to get route between user current location to the destination in iOS which also takes the course of the moving vehicle into consideration. Currently I am using the following function:
-(void)displayDirections{
CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:currentLocationLatitude longitude:currentLocationLongitude];
MKPlacemark *placemarker0 = [[MKPlacemark alloc]initWithCoordinate:currentLocation.coordinate];
MKMapItem *myMapItem0 = [[MKMapItem alloc] initWithPlacemark:placemarker0];
CLLocation *location = [[CLLocation alloc] initWithLatitude:destinationLocationLatitude longitude:destinationLocationLongitude]
MKPlacemark *placemarker1 = [[MKPlacemark alloc]initWithCoordinate:location.coordinate];
MKMapItem *myMapItem1 = [[MKMapItem alloc] initWithPlacemark:placemarker1];
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
[request setSource:myMapItem0];
[request setDestination:myMapItem1];
[request setTransportType:MKDirectionsTransportTypeAny];
[request setRequestsAlternateRoutes:YES]; // Gives you several route options.
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
__weak COMSiteDetailViewController *weakSelf = self;
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (!error) {
[weakSelf.mkMapView removeOverlays:weakSelf.mkMapView.overlays];
NSArray *routes = [response routes];
NSArray *sortedArray;
sortedArray = [routes sortedArrayUsingComparator:^NSComparisonResult(MKRoute *a, MKRoute *b) {
CLLocationDistance first = a.distance;
CLLocationDistance second = b.distance;
return first < second;
}];
int count = 1;
for (MKRoute *route in sortedArray) {
if(count < sortedArray.count){
route.polyline.title = #"longer";
}else{
route.polyline.title = #"shortest";
}
count++;
[self.mkMapView addOverlay:[route polyline] level:MKOverlayLevelAboveRoads];
}
}
}];
}
Thanks in advance!
After searching the web I have found that neither Google API or Apple MapKit Directions API consider the heading or movement of the vehicle while giving the route information. It just consider the coordinates of the start/end locations and give the shortest route(s).
So there is no way, at the moment, to display route considering vehicle heading using Apple/Google Apis.
Although, there are other paid Apis such as https://developer.here.com which I used in my app. This api is very reliable and the pricing too is very reasonable.
Thanks!
I receive MKLocalSearchCompletion items from MKLocalSearchCompleter to its delegate. Every MKLocalSearchCompletion contains a title and a subtitle, the subtitle is an address. I need to extract a city and a country from the address. Please help!
Please use the following code:
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = #"1 Infinite Loop Cupertino, CA 95014";
request.region = _mapView.region;
MKLocalSearch *search = [[MKLocalSearch alloc] initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
//NSLog(#"Map Items: %#", response.mapItems);
if (response.mapItems.count>0) {
for (MKMapItem *item in response.mapItems) {
//NSLog(#"Place: %#",[item valueForKey:#"place"]);
NSDictionary *dictStructuredAddress = [[[item valueForKey:#"place"] valueForKey:#"address"] valueForKey:#"structuredAddress"];
NSLog(#"Structured Address : %#",dictStructuredAddress);
NSLog(#"Country & City : %# & %#",[dictStructuredAddress valueForKey#"country"],[dictStructuredAddress valueForKey#"locality"]);
}
}];
Inside this dictStructuredAddress you can get country, city, etc.
MKLocalSearchCompletion does not "contain an address". It contains a title and subtitle. To get more information, use the MKLocalSearchCompletion to form an MKLocalSearchRequest and perform the MKLocalSearch.
I'm having a bug with the convertion of an NSString (which contains a place from a UITextField input) to a CLLocation.
Here is the method supposed to process the convertion:
- (void)geoCodeForAddress:(NSString *)address {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:address completionHandler:^(NSArray* placemarks, NSError* error){
dispatch_async(dispatch_get_main_queue(), ^{
CLPlacemark *placeMark = [placemarks lastObject];
if (placeMark.location != nil) {
self.actionLocation = placeMark.location;
} else {
self.actionLocation = nil;
}
if(self.event)
[self.tableView reloadData];
});
}];
}
My problem is, this method returns the wrong location for some specific strings. For instance, whenever I try to use "la patache paris" as an input, it returns a location in the wrong city though when I try the same exact string in Maps, it's finding the right place.
The method geocodeAddressString:completionHandler: is a CoreLocation method from the CLGeocoder class so there is no way I can see what's going on in it.
Would someone have some lead to find out why this is behaving weirdly ?
Thank you.
I have created a map that has an MKPointAnnotation which is the single point on the map (besides the users location). I am trying to work out how to amend some existing code I have to get the Driving directions to this point.
This is the code that I use early in the application. At this earlier point in the application I have the following which gives me a CLPlaceMark.
[geocoder geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
Collecting directions:
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
[request setSource:[MKMapItem mapItemForCurrentLocation]];
MKPlacemark *mkDest = [[MKPlacemark alloc] initWithPlacemark:topResult];
[request setDestination:[[MKMapItem alloc] initWithPlacemark:mkDest]];
[request setTransportType:MKDirectionsTransportTypeWalking]; // This can be limited to automobile and walking directions.
[request setRequestsAlternateRoutes:NO];
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (!error) {
for (MKRoute *route in [response routes]) {
[self.mapView addOverlay:[route polyline] level:MKOverlayLevelAboveRoads]; // Draws the route above roads, but below labels.
// You can also get turn-by-turn steps, distance, advisory notices, ETA, etc by accessing various route properties.
}
}
}];
Issue
The issue is that later on I seem to only be able to access the self.mapView.annotations. So I have access to the MKPointAnnotation, but I need access to a CLPlacemark for the setDestination on the MKDirectionsRequest.
So the question is how do I get a CLPacemark from a MKPointAnnotation, or is there a different approach to getting directions to a single point without that requirement? Thanks
For the directions request, the MKMapItem needs an MKPlacemark (not a CLPlacemark).
You can create an MKPlacemark directly from coordinates using its initWithCoordinate:addressDictionary: method.
For example:
MKPlacemark *mkDest = [[MKPlacemark alloc]
initWithCoordinate:pointAnnotation.coordinate
addressDictionary:nil];
[request setDestination:[[MKMapItem alloc] initWithPlacemark:mkDest]];
MKPointAnnotation will give you the coordinate, which you can put into CLPlacemark's location.coordinate. I don't think there will be any other readily-available information within an MKPointAnnotation that would be usable in a CLPlacemark.
MKPointAnnotation *annotation = ...;
CLPlacemark *placemark = ...;
placemark.location.coordinate = annotation.coordinate;
Edit: Apologies, I didn't realize that CLPlacemarks are largely read-only. That being said, you can use a reverse-geocode on the coordinate of your MKPointAnnotation in order to get a CLPlacemark. This link has information on how to reverse-geocode to get your CLPlacemark from a CLLocation (populate the location.coordinate with your annotation.coordinate) to look up directions.
You need to use the coordinate property of the MKPointAnnotation and then get the CLPlacemark via CLGeocoder using reverse geocode.
EDIT: Some sample code.
CLLocation *location = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
CLGeocoder *geocoder = [CLGeocoder new];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemark, NSError *error){
// Grab the placemark
}];
Otherwise you need to cache the CLPlacemark which you can do on your annotation datasource if you like (remember MKAnnotation is a protocol, there is nothing saying you can't add a property to the backing model).
I want to use MKLocalSearch for searching in a Map. This functionality is available in iOS 6.1+. Does anybody know how to use this or can anybody give an example of how to use an MKLocalSearch?
MKLocalSearchResponse documentation
The API for MKLocalSearch is fairly easy to understand. At its most basic, you
alloc-init an MKLocalSearchRequest
Set its naturalLanguageQuery to some search term
Use the search request to initialize an MKLocalSearch object
Tell the local search to start, passing it a completion handler
Do something with the array of MKMapItem objects in the response
Search for Cafes:
// Create a search request with a string
MKLocalSearchRequest *searchRequest = [[MKLocalSearchRequest alloc] init];
[searchRequest setNaturalLanguageQuery:#"Cafe"];
// Create the local search to perform the search
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:searchRequest];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
if (!error) {
for (MKMapItem *mapItem in [response mapItems]) {
NSLog(#"Name: %#, Placemark title: %#", [mapItem name], [[mapItem placemark] title]);
}
} else {
NSLog(#"Search Request Error: %#", [error localizedDescription]);
}
}];
You can specify a region for the search like this:
// Search for Cafes in Paris
MKLocalSearchRequest *searchRequest = [[MKLocalSearchRequest alloc] init];
[searchRequest setNaturalLanguageQuery:#"Cafe"];
CLLocationCoordinate2D parisCenter = CLLocationCoordinate2DMake(48.8566667, 2.3509871);
MKCoordinateRegion parisRegion = MKCoordinateRegionMakeWithDistance(parisCenter, 15000, 15000);
[searchRequest setRegion:parisRegion];
You can also take the region from an MKMapView that the user has zoomed into. This will give better results:
[searchRequest setRegion:self.mapView.region];
The response object, an MKLocalSearchResponse, contains an array of MKMapItem objects (mapItems) and an MKCoordinateRegion called boundingRegion, which is a region that contains all the results. You can use it to set a map view to show all results:
[self.mapView setRegion:response.boundingRegion];
The array of MKMapItem objects can't be placed on a map (they're used for sending to the Maps app) but each contains a placemark property which can be added to a map:
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
if (!error) {
for (MKMapItem *mapItem in [response mapItems]) {
NSLog(#"Name: %#, MKAnnotation title: %#", [mapItem name], [[mapItem placemark] title]);
NSLog(#"Coordinate: %f %f", [[mapItem placemark] coordinate].latitude, [[mapItem placemark] coordinate].longitude);
// Should use a weak copy of self
[self.mapView addAnnotation:[mapItem placemark]];
}
} else {
NSLog(#"Search Request Error: %#", [error localizedDescription]);
}
}];
Search for Dublin places a pin on the map view and logs:
Name: Dublin, Co. Dublin, MKAnnotation title: Dublin, Co. Dublin, Ireland
Coordinate: 53.344104 -6.267494
There are a load of extra details in the returned objects, especially if you search for businesses. Here are a few:
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
if (!error) {
NSLog(#"Results: %#", [response mapItems]);
MKMapItem *mapItem = [[response mapItems] objectAtIndex:0];
NSLog(#"Name:%# Phone:%# URL:%#", [mapItem name], [mapItem phoneNumber], [mapItem url]);
NSLog(#"Placemark: %#", [mapItem placemark]);
MKPlacemark *placemark = [mapItem placemark];
NSLog(#"Placemark Address: %#", [placemark addressDictionary]);
MKCoordinateRegion boundingRegion = [response boundingRegion];
NSLog(#"Bounds: %f %f", boundingRegion.span.latitudeDelta, boundingRegion.span.longitudeDelta);
}
Here is an example that search for cafes in a radius of 1 km around a given location :
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(11.567898, 104.894430);
request.naturalLanguageQuery = #"cafe";
request.region = MKCoordinateRegionMakeWithDistance(location, 1000, 1000);
MKLocalSearch *search = [[MKLocalSearch alloc] initWithRequest:request];
[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){
for (MKMapItem *item in response.mapItems) {
NSLog(#"%#", item.name);
}
}];
Please note than when the search is unsuccessful, it does not return an empty list, but an error with domain MKErrorDomain and code 4.
Here is a tutorial for Localsearch
http://jeffreysambells.com/2013/01/28/mklocalsearch-example