Google Maps - Make route line follow streets when map zoomed in - ios

I'm getting the same issue as described in following SO questions:
(The route lines is not following the streets when I zoom in)
MapKit - Make route line follow streets when map zoomed in
and
Route drawing on Google Maps for iOS not following the street lines
But seems there are no any answer which solved mentioned issue.
I'm adding to points to the my GMSMapView map by following function:
-(void) addPointToMap:(CLLocationCoordinate2D) coordinate
{
CLLocationCoordinate2D position = CLLocationCoordinate2DMake(
coordinate.latitude,
coordinate.longitude);
GMSMarker *marker = [GMSMarker markerWithPosition:position];
marker.map = mapView_;
[waypoints_ addObject:marker];
NSString *positionString = [[NSString alloc] initWithFormat:#"%f,%f",
coordinate.latitude,coordinate.longitude];
[waypointStrings_ addObject:positionString];
if([waypoints_ count]>1){
NSString *sensor = #"false";
NSArray *parameters = [NSArray arrayWithObjects:sensor, waypointStrings_,
nil];
NSArray *keys = [NSArray arrayWithObjects:#"sensor", #"waypoints", nil];
NSDictionary *query = [NSDictionary dictionaryWithObjects:parameters
forKeys:keys];
MDDirectionService *mds=[[MDDirectionService alloc] init];
SEL selector = #selector(addDirections:);
[mds setDirectionsQuery:query
withSelector:selector
withDelegate:self];
}
}
and here are setDirectionsQuery function:
static NSString *kMDDirectionsURL = #"http://maps.googleapis.com/maps/api/directions/json?";
- (void)setDirectionsQuery:(NSDictionary *)query withSelector:(SEL)selector
withDelegate:(id)delegate{
NSArray *waypoints = [query objectForKey:#"waypoints"];
NSString *origin = [waypoints objectAtIndex:0];
int waypointCount = [waypoints count];
int destinationPos = waypointCount -1;
NSString *destination = [waypoints objectAtIndex:destinationPos];
NSString *sensor = [query objectForKey:#"sensor"];
NSMutableString *url =
[NSMutableString stringWithFormat:#"%#&origin=%#&destination=%#&sensor=%#",
kMDDirectionsURL,origin,destination, sensor];
if(waypointCount>2) {
[url appendString:#"&waypoints=optimize:true"];
int wpCount = waypointCount-2;
for(int i=1;i<wpCount;i++){
[url appendString: #"|"];
[url appendString:[waypoints objectAtIndex:i]];
}
}
url = [url
stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding];
_directionsURL = [NSURL URLWithString:url];
[self retrieveDirections:selector withDelegate:delegate];
}
Note: I have followed this Google tutorial and modified it a little bit:
https://www.youtube.com/watch?v=AdV7bCWuDYg
Thanks in advance, any help will be appreciated!

Finally I have found solution, Thanks to the WWJD's last edit in his question!
Route drawing on Google Maps for iOS not following the street lines
From the answer:
What I basically did before was that I was getting and working only with the information I'm receiving in the routes while if you check the JSON file you're receiving from Google Directions API, you'll see that you receive much more information in the and the . This is the information we need to produce the proper results and the right polyline.

Related

NSMutableArray parsing csv not working?

I have this code where I use NSMutableArray to parse a csv file. There are no errors that stop me from running the app however the map doesn't display anything.
NSString *csvFilePath = [[NSBundle mainBundle] pathForResource:#"Data2" ofType:#"csv"];
NSString *dataStr = [NSString stringWithContentsOfFile:csvFilePath encoding:NSUTF8StringEncoding error:nil];
NSMutableArray *allLinedStrings = [[NSMutableArray alloc]initWithArray:[dataStr componentsSeparatedByString:#"\r"]];
NSMutableArray *latitude = [[NSMutableArray alloc]init];
NSMutableArray *longitude = [[NSMutableArray alloc]init];
NSMutableArray *description = [[NSMutableArray alloc]init];
NSMutableArray *address = [[NSMutableArray alloc]init];
NSMutableArray *temperature = [[NSMutableArray alloc]init];
NSMutableArray *time = [[NSMutableArray alloc]init];
NSMutableArray *ambient = [[NSMutableArray alloc]init];
NSMutableArray *filteredLocations = [NSMutableArray array];
MKMapPoint* pointArr = malloc(sizeof(MKMapPoint) * filteredLocations.count);
for (int idx = 0; idx < [allLinedStrings count]; idx++)
{
NSMutableArray *infos = [[NSMutableArray alloc]initWithArray:[[allLinedStrings objectAtIndex:idx] componentsSeparatedByString:#","]];
if ([infos count] > 1)
{
[latitude addObject:[infos objectAtIndex:4]];
[longitude addObject:[infos objectAtIndex:5]];
[description addObject:[infos objectAtIndex:0]];
[address addObject:[infos objectAtIndex:10]];
[temperature addObject:[infos objectAtIndex:6]];
[time addObject:[infos objectAtIndex:15]];
[ambient addObject:[infos objectAtIndex:8]];
if([[latitude objectAtIndex:4] isEqualToString:#"NULL"] || [[longitude objectAtIndex:5] isEqualToString:#"NULL"] || [[description objectAtIndex:0] isEqualToString:#"NULL"] || [[address objectAtIndex:10]isEqualToString:#"NULL"] || [[temperature objectAtIndex:6] isEqualToString:#"NULL"] || [[time objectAtIndex:15]isEqualToString:#"NULL"] || [[ambient objectAtIndex:8] isEqualToString:#"NULL"]) {continue;}
CLLocationCoordinate2D coordinate;
coordinate.latitude = [[latitude objectAtIndex:4] doubleValue];
coordinate.longitude = [[longitude objectAtIndex:5] doubleValue];
Location *annotation = [[Location alloc] initWithName:[description objectAtIndex:0] address:[address objectAtIndex:10] temperature:[temperature objectAtIndex:6] time:[time objectAtIndex:15] ambient:[ambient objectAtIndex:8] coordinate:coordinate] ;
[mapview addAnnotation:annotation];
[filteredLocations addObject:annotation];
MKMapPoint point = MKMapPointForCoordinate(coordinate);
pointArr[idx] = point;
}
}
self.routeLine = [MKPolyline polylineWithPoints:pointArr count:filteredLocations.count];
[self.mapview addOverlay:self.routeLine];
free(pointArr);
MKMapRect zoomRect = MKMapRectNull;
for (id <MKAnnotation> annotation in mapview.annotations)
{
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
zoomRect = MKMapRectUnion(zoomRect, pointRect);
}
[mapview setVisibleMapRect:zoomRect animated:YES];
self.mapview.delegate = self;
}
I guess there must be something wrong with how I'm calling the objects or maybe the MKMapPoint but I don't manage to find what's blocking the app from displaying the data. I've tried using both "initWithObjects" and removing "if ([infos count] > 1){" but when ran it crashed showing a breakdown point in "NSMutableArray *latitude = [[NSMutableArray alloc]init];".
Based on your previous questions about this project, you want to do the following at a high level:
Parse a CSV file where each line has coordinate data. Ignore lines that have "null" data. (For the purpose of this answer, let's ignore that one could use a pre-built CSV parser, or use a different format altogether.)
Show annotations for lines with "good" data.
Connect all the annotations with a line.
For requirement 1 (R1), you already know how to load the CSV file, loop through the lines, and identify the lines with "null" data.
For requirement 2 (R2), after some research, you know that you can create and add annotations to the map one at a time and the map doesn't need to know ahead of time how many you will add so that means the first two requirements could be done in the same loop.
For requirement 3 (R3), after some research, you know that to create and add a polyline to the map, you need to know ahead of time how many points will be in the line.
For R1 and R2, you will be looping through the lines of the CSV and identify the non-null lines.
So that means you will know how many points will be in the polyline after the loop that handles R1 and R2. That means the polyline must be created after that loop.
But to create the polyline, you need not just the point count but the coordinates for each point as well.
That means while looping through the lines in the CSV, you need to save the coordinate data somewhere (in the same order it appeared in the CSV).
In Objective-C, a convenient structure that allows you to add data to it without knowing in advance how many objects will be added is an NSMutableArray.
So now we have this very high-level plan:
Loop through the CSV file, ignore lines with null data, create and add annotations, add the line data to an NSMutableArray (NSMA).
Create a polyline using the point data in NSMA, add the polyline to the map.
With this plan, we see we need one NSMutableArray. Notice that in the existing code, you have a Location class that holds (or could hold) all the data from each line of the CSV.
That means we could simply add these Location objects to the NSMA. NSMutableArrays can hold any type of object (they don't have to be just NSStrings).
So here's a slightly more detailed plan:
Initialize an NSMutableArray called filteredLocations (eg. NSMutableArray *filteredLocations = [NSMutableArray array];).
Loop through the CSV file, ignore lines with null data, create a Location object and add as an annotation, add the Location object to filteredLocations (eg. [filteredLocations addObject:annotation];).
Initialize (malloc) a C array to hold the points of the polyline with the point count being the count of filteredLocations.
Loop through filteredLocations, add point from filteredLocations to the C array.
Create and add a polyline to the map.
In this plan note we have two separate loops: The first one is for R1 and R2. The second one is for R3.
If required, I will post sample code that implements this plan.
First, just to explain your latest NSRangeException error, it is happening on this line:
if([[latitude objectAtIndex:4] isEqualToString:#"NULL"] || ...
because you've declared latitude as an array and the first time the if executes in the loop, latitude only has one object (a few lines above this if you do [latitude addObject:...). The index of an array starts at zero so the bounds of an array with one object are zero to zero hence the error message saying index 4 beyond bounds [0 .. 0].
There are many other issues with the rest of the code.
There is not enough room in this answer to explain in detail.
I urge you, if possible, to stop, step back and re-start with a much simpler project or tutorials and, most importantly, learn the absolute basics of programming in general.
Here is an example of code that should work based on your sample data:
-(void)viewDidLoad
{
[super viewDidLoad];
self.mapview.delegate = self;
NSString *csvFilePath = [[NSBundle mainBundle] pathForResource:#"Data2" ofType:#"csv"];
NSString *dataStr = [NSString stringWithContentsOfFile:csvFilePath encoding:NSUTF8StringEncoding error:nil];
NSArray *allLinedStrings = [dataStr componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSMutableArray *filteredLocations = [NSMutableArray array];
for (int idx = 0; idx < [allLinedStrings count]; idx++)
{
NSArray *infos = [[allLinedStrings objectAtIndex:idx] componentsSeparatedByString:#","];
if ([infos count] > 15)
{
NSString *latitude = [infos objectAtIndex:4];
NSString *longitude = [infos objectAtIndex:5];
NSString *description = [infos objectAtIndex:0];
NSString *address = [infos objectAtIndex:10];
NSString *temperature = [infos objectAtIndex:6];
NSString *time = [infos objectAtIndex:15];
NSString *ambient = [infos objectAtIndex:8];
if([latitude isEqualToString:#"NULL"]
|| [longitude isEqualToString:#"NULL"]
|| [description isEqualToString:#"NULL"]
|| [address isEqualToString:#"NULL"]
|| [temperature isEqualToString:#"NULL"]
|| [time isEqualToString:#"NULL"]
|| [ambient isEqualToString:#"NULL"])
{
continue;
}
CLLocationCoordinate2D coordinate;
coordinate.latitude = [latitude doubleValue];
coordinate.longitude = [longitude doubleValue];
Location *annotation = [[Location alloc] initWithName:description
address:address
temperature:temperature
time:time
ambient:ambient
coordinate:coordinate];
[mapview addAnnotation:annotation];
[filteredLocations addObject:annotation];
}
}
MKMapPoint* pointArr = malloc(sizeof(MKMapPoint) * filteredLocations.count);
for (int flIndex = 0; flIndex < filteredLocations.count; flIndex++)
{
Location *location = [filteredLocations objectAtIndex:flIndex];
MKMapPoint point = MKMapPointForCoordinate(location.coordinate);
pointArr[flIndex] = point;
}
self.routeLine = [MKPolyline polylineWithPoints:pointArr count:filteredLocations.count];
[self.mapview addOverlay:self.routeLine];
free(pointArr);
[self.mapview showAnnotations:self.mapview.annotations animated:YES];
}

Attempting to drop pins based on MKMap from values from array

As the question says I am trying to add pins to my map based on the coordinates returned by my php file. Said file returns the following results
[{"dogid":"1","latitude":"15.435786","longitude":"-21.318447"},{"dogid":"1","latitude":"14.00000","longitude":"-18.536711"}]
What I am doing (well I believe i am) is taking the values from the link and saving them to a string. Secondly, save that string value to an array. Then, I go thru this array and save out the latitude and longitude and assign it to CLLocationCordinate 2dcoord. After whch I expect both pins to be dropped on whatever location they received.
However, what occurs is: Upon running the program, when it arrives on this lin
for (NSDictionary *row in locations) {
the loop is not run to assign the values, and it jumps to the end. Oddly, a single pin is dropped on the map (thou location doesnt appear to be the values that it waas passed).
Would appreciate a little incite into the matter.
Thanks
- (void)viewDidAppear:(BOOL)animated
{
NSMutableArray *annotations = [[NSMutableArray alloc] init];
NSURL *myURL =[NSURL URLWithString:#"link.php"];
NSError *error=nil;
NSString *str=[NSString stringWithContentsOfURL:myURL encoding:NSUTF8StringEncoding error:&error];
CLLocationCoordinate2D coord;
NSArray *locations=[NSArray arrayWithContentsOfFile:str];
for (NSDictionary *row in locations) {
NSNumber *latitude = [row objectForKey:#"latitude"];
NSNumber *longitude = [row objectForKey:#"longitude"];
// NSString *title = [row objectForKey:#"title"];
//Create coordinates from the latitude and longitude values
coord.latitude = latitude.doubleValue;
coord.longitude = longitude.doubleValue;
}
MKPointAnnotation *pin = [[MKPointAnnotation alloc] init];
pin.coordinate = coord;
[self.mapView addAnnotation:pin];
}
It looks like you are trying to save api response to and Array.
Api always returns json string which is NSString.
You need to convert decode json string.
In your case
NSString *str=[NSString stringWithContentsOfURL:myURL encoding:NSUTF8StringEncoding error:&error];
you need to decode str with [NSJSONSerialization JSONObjectWithData:<#(NSData )#> options:<#(NSJSONReadingOptions)#> error:<#(NSError *)#>] which give you proper array of dictionary.
Hope it will help you

Search on Google Map Sdk

I need to implement the map view in my app to locate the required place. I had tried with the SVGeocoder concept.
[SVGeocoder geocode:searchfield.text
completion:^(NSArray *placemarks, NSHTTPURLResponse *urlResponse, NSError *error) {
}
But suppose I am trying to search any restaurent then the result is nil.
I was looking on Google map sdk but don't know how to do search functionality on GMSCameraPosition class.
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:latitude
longitude:longitude
zoom:5];
how to search with the address using google sdk.
Thanks in advance.
If I understood it correctly, you need the location co-ordinates from a address string. Its Forward geo-coding. You can take a look at Google's free api for this: Link1
You will need a API key from your google account to access this api and there is way to select a free or business plan depending on your number of requests.
You need to use a CLLocation object for getting co-ordinates from your address. I wrote a similar function. CLLocation* temp_location=[[CLLocation alloc]init];
temp_location=[GeoCoding findAddressCordinates:sourceAddressTxtField.text];
// Class GeoCoding to find Co-ordinates
#import <Foundation/Foundation.h>
#interface GeoCoding : NSObject {
}
+(CLLocation*)findAddressCordinates:(NSString*)addressString;
#end
#import "GeoCoding.h"
#import <CoreLocation/CLAvailability.h>
#implementation GeoCoding
+(CLLocation*)findAddressCordinates:(NSString*)addressString {
CLLocation *location;
NSString *url = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#&sensor=true", addressString];
url = [url stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
NSURL *wurl = [NSURL URLWithString:url];
NSData *data = [NSData dataWithContentsOfURL: wurl];
// Fail to get data from server
if (nil == data) {
NSLog(#"Error: Fail to get data");
}
else{
// Parse the json data
NSError *error;
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&error];
// Check status of result
NSString *resultStatus = [json valueForKey:#"status"];
// If responce is valid
if ( (nil == error) && [resultStatus isEqualToString:#"OK"] ) {
NSDictionary *locationDict=[json objectForKey:#"results"] ;
NSArray *temp_array=[locationDict valueForKey:#"geometry"];
NSArray *temp_array2=[temp_array valueForKey:#"location"];
NSEnumerator *enumerator = [temp_array2 objectEnumerator];
id object;
while ((object = [enumerator nextObject])) {
double latitude=[[object valueForKey:#"lat"] doubleValue];
double longitude=[[object valueForKey:#"lng"] doubleValue];
location=[[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
NSLog(#"CLLocation lat is %f -------------& long %f",location.coordinate.latitude, location.coordinate.longitude);
}
}
}
return location;
}
#end
You can then use this co-ordinates in your Google Map to focus your camera position.

plot marker on Google Maps iOS from JSON file

I would like to plot markers on Google Maps for iOS, and this by including JSON file that will includes longitude and latitude. I can do it manually in the code, by replacing the values.
The problem is that I don't know how to show new markers on the map from JSON file.
Here is my code :
- (void)addDefaultMarkers {
// Add a custom 'glow' marker around Sydney.
GMSMarker *sydneyMarker = [[GMSMarker alloc] init];
sydneyMarker.title = #"Sydney!";
sydneyMarker.icon = [UIImage imageNamed:#"glow-marker"];
sydneyMarker.position = CLLocationCoordinate2DMake(25.062718, 55.130761);
sydneyMarker.map = mapView_;
GMSMarker *melbourneMarker = [[GMSMarker alloc] init];
melbourneMarker.title = #"Melbourne!";
melbourneMarker.icon = [UIImage imageNamed:#"arrow"];
melbourneMarker.position = CLLocationCoordinate2DMake(25.100822, 55.17467);
melbourneMarker.map = mapView_;
}
Any ideas on how to do it ?
chech my question in this link, stackoverflow.com/questions/20902732/…. This link will help,
First of all parse the json data. And collect it as array or dictionary, then U can directly plot the value in map
The first two lines are to parse the data into an array
SBJsonParser *jsonParser = [SBJsonParser new];
NSArray *jsonData = (NSArray *) [jsonParser objectWithString:outputData error:nil];
then, the loop should continue till the no. of values,
for(int i=0;i<[jsonData count];i++)
{
NSDictionary *dict=(NSDictionary *)[jsonData objectAtIndex:i];
Nslog(#"%#",dict);
double la=[[dict objectForKey:#"latitude"] doubleValue];
double lo=[[dict objectForKey:#"longitude"] doubleValue];
CLLocation * loca=[[CLLocation alloc]initWithLatitude:la longitude:lo];
CLLocationCoordinate2D coordi=loca.coordinate;
marker=[GMSMarker markerWithPosition:coordi];
marker.snippet = #"Hello World";
marker.animated = YES;
marker.map = mapView;
}

CLGeocoder ever return one placemark

I want to revive this and this question because the problem still persists for me, so I'm writing a new question.
This is my code:
- (SVGeocoder*)initWithParameters:(NSMutableDictionary*)parameters completion:(SVGeocoderCompletionHandler)block {
self = [super init];
self.operationCompletionBlock = block;
Class cl = NSClassFromString(#"CLGeocoder");
if (cl != nil)
{
if (self.geocoder_5_1 == nil) {
self.geocoder_5_1 = [[cl alloc] init];
}
NSString *address = [parameters objectForKey:kGeocoderAddress];
[self.geocoder_5_1 geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
NSMutableArray *svplacemarks = [NSMutableArray arrayWithCapacity:1];
SVPlacemark *placemark;
NSLog(#"placemarks[count] = %i", [placemarks count]);
for (CLPlacemark *mark in placemarks) {
placemark = [[SVPlacemark alloc] initWithPlacemark:mark];
[svplacemarks addObject:placemark];
}
self.operationCompletionBlock([NSArray arrayWithArray:svplacemarks],nil,error);
}];
}
else
{
self.operationRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://maps.googleapis.com/maps/api/geocode/json"]];
[self.operationRequest setTimeoutInterval:kSVGeocoderTimeoutInterval];
[parameters setValue:#"true" forKey:kGeocoderSensor];
[parameters setValue:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode] forKey:kGeocoderLanguage];
[self addParametersToRequest:parameters];
self.state = SVGeocoderStateReady;
}
return self;
}
It is my personal version (quite rough) of SVGeocoder using CLGeocoder for forward geocoding with retrocompatibility for iOS < 5.1
I use this solution because of the Google terms which prevent the use of the maps API without showing the result on a Google map.
The problem is the same one from the previously mentioned questions: CLGeocoder returns only one placemark and the log prints a nice
"placemarks[count] = 1".
My question is, does anyone know if there is another way to retrieve forward geocoding, or some other magic thing (the Apple map app shows multiple markers for the same query I do, "via roma", for example) ?
EDIT FOR ROB'S SOLUTION
Class mkLocalSearch = NSClassFromString(#"MKLocalSearch");
if (mkLocalSearch != nil)
{
NSString *address = [parameters objectForKey:kGeocoderAddress];
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.region = MKCoordinateRegionForMapRect(MKMapRectWorld);
request.naturalLanguageQuery = address;
MKLocalSearch *localsearch = [[MKLocalSearch alloc] initWithRequest:request];
[localsearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
NSMutableArray *svplacemarks = [NSMutableArray arrayWithCapacity:1];
SVPlacemark *placemark;
NSLog(#"response.mapItems[count] = %i", [response.mapItems count]);
for (MKMapItem *item in response.mapItems)
{
placemark = [[SVPlacemark alloc] initWithPlacemark:item.placemark];
[svplacemarks addObject:placemark];
}
self.operationCompletionBlock([NSArray arrayWithArray:svplacemarks],nil,error);
}];
}
This is an interesting solution that gives another point of view. Unfortunately, even if I set the region to worldwide, I still get a nice log
response.mapItems[count] = 1
The query was "via roma", which is a very common street name in Italy, so much so that I think we can find it in practically any Italian city.
Maybe I'm doing something wrong?
EDIT 2 - New Test:
convert World Rect to CLRegion, code from here
NSString *address = [parameters objectForKey:kGeocoderAddress];
// make a conversion from MKMapRectWorld to a regular CLRegion
MKMapRect mRect = MKMapRectWorld;
MKMapPoint neMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), mRect.origin.y);
MKMapPoint swMapPoint = MKMapPointMake(mRect.origin.x, MKMapRectGetMaxY(mRect));
float ewDelta= neMapPoint.x - swMapPoint.x;
float nsDelta= swMapPoint.y - neMapPoint.y;
MKMapPoint cMapPoint = MKMapPointMake(ewDelta / 2 + swMapPoint.x, nsDelta / 2 + neMapPoint.y);
CLLocationCoordinate2D neCoord = MKCoordinateForMapPoint(neMapPoint);
CLLocationCoordinate2D swCoord = MKCoordinateForMapPoint(swMapPoint);
CLLocationCoordinate2D centerCoord = MKCoordinateForMapPoint(cMapPoint);
CLLocationDistance diameter = [self getDistanceFrom:neCoord to:swCoord];
// i don't have the map like showed in the example so i'm trying to center the search area to the hypothetical center of the world
CLRegion *clRegion = [[CLRegion alloc] initCircularRegionWithCenter:centerCoord radius:(diameter/2) identifier:#"worldwide"];
[self.geocoder_5_1 geocodeAddressString:address inRegion: clRegion completionHandler:^(NSArray *placemarks, NSError *error) {
NSMutableArray *svplacemarks = [NSMutableArray arrayWithCapacity:1];
SVPlacemark *placemark;
NSLog(#"placemarks[count] = %i", [placemarks count]);
for (CLPlacemark *mark in placemarks) {
placemark = [[SVPlacemark alloc] initWithPlacemark:mark];
[svplacemarks addObject:placemark];
}
self.operationCompletionBlock([NSArray arrayWithArray:svplacemarks],nil,error);
}];
... and I get the usual "placemark [count] = 1"
Obviously, CLGeocoder will return multiple placemarks if the address gets multiple hits (i.e. the region is large enough such that the simple street address is ambiguous), but frequently it will find just the one match if the region is small enough or if the supplied address is unique enough.
While it's not a general purpose solution, effective iOS 6.1, you have MKLocalSearch, which does a more general lookup (including names of businesses, etc.):
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.region = self.mapView.region;
request.naturalLanguageQuery = textField.text;
MKLocalSearch *localsearch = [[MKLocalSearch alloc] initWithRequest:request];
[localsearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
for (MKMapItem *item in response.mapItems)
{
Annotation *annotation = [[Annotation alloc] initWithPlacemark:item.placemark];
annotation.title = item.name;
annotation.phone = item.phoneNumber;
annotation.subtitle = item.placemark.addressDictionary[(NSString *)kABPersonAddressStreetKey];
[self.mapView addAnnotation:annotation];
}
}];
I guess it all depends upon what sort of multiple hits you're expecting to receive.
There are some addresses for which CLGeocoder does return multiple placemarks. One example I've found is "Herzel 13, Haifa, Israel". I use the geocodeAddressDictionary:completionHandler: method, and get the same 2 results for the address (it can be set either as street/city/country, or just as a street - the results are the same).
It's just pretty hard to find such examples, and they may change in the future of course. For some reason, the Apple maps app shows the "Did you mean..." dialog for many more addresses.

Resources