How can I get latitude and longitude from a full address (street, city, etc.) input by the user, using the iPhone SDK 3.x?
Here's an updated, more compact, version of unforgiven's code, which uses the latest v3 API:
- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)address
{
double latitude = 0, longitude = 0;
NSString *esc_addr = [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *req = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%#", esc_addr];
NSString *result = [NSString stringWithContentsOfURL:[NSURL URLWithString:req] encoding:NSUTF8StringEncoding error:NULL];
if (result) {
NSScanner *scanner = [NSScanner scannerWithString:result];
if ([scanner scanUpToString:#"\"lat\" :" intoString:nil] && [scanner scanString:#"\"lat\" :" intoString:nil]) {
[scanner scanDouble:&latitude];
if ([scanner scanUpToString:#"\"lng\" :" intoString:nil] && [scanner scanString:#"\"lng\" :" intoString:nil]) {
[scanner scanDouble:&longitude];
}
}
}
CLLocationCoordinate2D center;
center.latitude = latitude;
center.longitude = longitude;
return center;
}
It makes the assumption that the coordinates for "location" come first, e.g. before those for "viewport", because it just takes the first coords it finds under the "lng" and "lat" keys. Feel free to use a proper JSON scanner (e.g. SBJSON) if you are worried about this simple scanning technique used here.
You can use Google Geocoding for this. It is as simple as getting data through HTTP and parsing it (it can return JSON KML, XML, CSV).
Here's a similar solution for obtaining the latitude and longitude from Google. Note: This example uses the SBJson library, which you can find on github:
+ (CLLocationCoordinate2D) geoCodeUsingAddress: (NSString *) address
{
CLLocationCoordinate2D myLocation;
// -- modified from the stackoverflow page - we use the SBJson parser instead of the string scanner --
NSString *esc_addr = [address stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
NSString *req = [NSString stringWithFormat: #"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%#", esc_addr];
NSDictionary *googleResponse = [[NSString stringWithContentsOfURL: [NSURL URLWithString: req] encoding: NSUTF8StringEncoding error: NULL] JSONValue];
NSDictionary *resultsDict = [googleResponse valueForKey: #"results"]; // get the results dictionary
NSDictionary *geometryDict = [ resultsDict valueForKey: #"geometry"]; // geometry dictionary within the results dictionary
NSDictionary *locationDict = [ geometryDict valueForKey: #"location"]; // location dictionary within the geometry dictionary
// -- you should be able to strip the latitude & longitude from google's location information (while understanding what the json parser returns) --
DLog (#"-- returning latitude & longitude from google --");
NSArray *latArray = [locationDict valueForKey: #"lat"]; NSString *latString = [latArray lastObject]; // (one element) array entries provided by the json parser
NSArray *lngArray = [locationDict valueForKey: #"lng"]; NSString *lngString = [lngArray lastObject]; // (one element) array entries provided by the json parser
myLocation.latitude = [latString doubleValue]; // the json parser uses NSArrays which don't support "doubleValue"
myLocation.longitude = [lngString doubleValue];
return myLocation;
}
Update version, using iOS JSON:
- (CLLocationCoordinate2D)getLocation:(NSString *)address {
CLLocationCoordinate2D center;
NSString *esc_addr = [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *req = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%#", esc_addr];
NSData *responseData = [[NSData alloc] initWithContentsOfURL:
[NSURL URLWithString:req]]; NSError *error;
NSMutableDictionary *responseDictionary = [NSJSONSerialization
JSONObjectWithData:responseData
options:nil
error:&error];
if( error )
{
NSLog(#"%#", [error localizedDescription]);
center.latitude = 0;
center.longitude = 0;
return center;
}
else {
NSArray *results = (NSArray *) responseDictionary[#"results"];
NSDictionary *firstItem = (NSDictionary *) [results objectAtIndex:0];
NSDictionary *geometry = (NSDictionary *) [firstItem objectForKey:#"geometry"];
NSDictionary *location = (NSDictionary *) [geometry objectForKey:#"location"];
NSNumber *lat = (NSNumber *) [location objectForKey:#"lat"];
NSNumber *lng = (NSNumber *) [location objectForKey:#"lng"];
center.latitude = [lat doubleValue];
center.longitude = [lng doubleValue];
return center;
}
}
The following method does what you asked for. You need to insert your Google maps key for this to work correctly.
- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)address{
int code = -1;
int accuracy = -1;
float latitude = 0.0f;
float longitude = 0.0f;
CLLocationCoordinate2D center;
// setup maps api key
NSString * MAPS_API_KEY = #"YOUR GOOGLE MAPS KEY HERE";
NSString *escaped_address = [address stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
// Contact Google and make a geocoding request
NSString *requestString = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#&output=csv&oe=utf8&key=%#&sensor=false&gl=it", escaped_address, MAPS_API_KEY];
NSURL *url = [NSURL URLWithString:requestString];
NSString *result = [NSString stringWithContentsOfURL: url encoding: NSUTF8StringEncoding error:NULL];
if(result){
// we got a result from the server, now parse it
NSScanner *scanner = [NSScanner scannerWithString:result];
[scanner scanInt:&code];
if(code == 200){
// everything went off smoothly
[scanner scanString:#"," intoString:nil];
[scanner scanInt:&accuracy];
//NSLog(#"Accuracy: %d", accuracy);
[scanner scanString:#"," intoString:nil];
[scanner scanFloat:&latitude];
[scanner scanString:#"," intoString:nil];
[scanner scanFloat:&longitude];
center.latitude = latitude;
center.longitude = longitude;
return center;
}
else{
// the server answer was not the one we expected
UIAlertView *alert = [[[UIAlertView alloc]
initWithTitle: #"Warning"
message:#"Connection to Google Maps failed"
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:#"OK", nil] autorelease];
[alert show];
center.latitude = 0.0f;
center.longitude = 0.0f;
return center;
}
}
else{
// no result back from the server
UIAlertView *alert = [[[UIAlertView alloc]
initWithTitle: #"Warning"
message:#"Connection to Google Maps failed"
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:#"OK", nil] autorelease];
[alert show];
center.latitude = 0.0f;
center.longitude = 0.0f;
return center;
}
}
center.latitude = 0.0f;
center.longitude = 0.0f;
return center;
}
For the google map key solution, as described by unforgiven above, doesn't one has to make the app free? As per google terms & conditions: 9.1 Free, Public Accessibility to Your Maps API Implementation. Your Maps API Implementation must be generally accessible to users without charge.
With map kit in sdk 3.0 this is easily done using the SDK. See apple's manuals or follow: https://developer.apple.com/documentation/mapkit
There's also CoreGeoLocation, which wraps up the functionality in a framework (Mac) or static library (iPhone). Supports lookups through Google or Yahoo, if you have a preference for one over the other.
https://github.com/thekarladam/CoreGeoLocation
- (void)viewDidLoad
{
app=(AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"%#", app.str_address);
NSLog(#"internet connect");
NSString *Str_address=_txt_zipcode.text;
double latitude1 = 0, longitude1 = 0;
NSString *esc_addr = [ Str_address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *req = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%#", esc_addr];
NSString *result = [NSString stringWithContentsOfURL:[NSURL URLWithString:req] encoding:NSUTF8StringEncoding error:NULL];
if (result)
{
NSScanner *scanner = [NSScanner scannerWithString:result];
if ([scanner scanUpToString:#"\"lat\" :" intoString:nil] && [scanner scanString:#"\"lat\" :" intoString:nil])
{
[scanner scanDouble:&latitude1];
if ([scanner scanUpToString:#"\"lng\" :" intoString:nil] && [scanner scanString:#"\"lng\" :" intoString:nil])
{
[scanner scanDouble:&longitude1];
}
}
}
//in #.hfile
// CLLocationCoordinate2D lat;
// CLLocationCoordinate2D lon;
// float address_latitude;
// float address_longitude;
lat.latitude=latitude1;
lon.longitude=longitude1;
address_latitude=lat.latitude;
address_longitude=lon.longitude;
}
func geoCodeUsingAddress(address: NSString) -> CLLocationCoordinate2D {
var latitude: Double = 0
var longitude: Double = 0
let addressstr : NSString = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=\(address)" as NSString
let urlStr = addressstr.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let searchURL: NSURL = NSURL(string: urlStr! as String)!
do {
let newdata = try Data(contentsOf: searchURL as URL)
if let responseDictionary = try JSONSerialization.jsonObject(with: newdata, options: []) as? NSDictionary {
print(responseDictionary)
let array = responseDictionary.object(forKey: "results") as! NSArray
let dic = array[0] as! NSDictionary
let locationDic = (dic.object(forKey: "geometry") as! NSDictionary).object(forKey: "location") as! NSDictionary
latitude = locationDic.object(forKey: "lat") as! Double
longitude = locationDic.object(forKey: "lng") as! Double
}} catch {
}
var center = CLLocationCoordinate2D()
center.latitude = latitude
center.longitude = longitude
return center
}
Related
I am new in iOS and I am facing problem regarding to get current value of string from array.
My code is like this
loginStatusHS = [[NSString alloc] initWithBytes: [myNSMDatalatetudeFromServer mutableBytes] length:[myNSMDatalatetudeFromServer length] encoding:NSUTF8StringEncoding];
NSLog(#"loginStatus =%#",loginStatusHS);
NSError *parseError = nil;
NSDictionary *xmlDictionary = [XMLReader dictionaryForXMLString:loginStatusHS error:&parseError];
NSLog(#"JSON DICTIONARY = %#",xmlDictionary);
recordResultHS = [xmlDictionary[#"success"] integerValue];
NSLog(#"Success: %ld",(long)recordResultHS);
NSDictionary* Address=[xmlDictionary objectForKey:#"soap:Envelope"];
NSLog(#"Address Dict = %#",Address);
NSDictionary *new =[Address objectForKey:#"soap:Body"];
NSLog(#"NEW DICT =%#",new);
NSDictionary *LoginResponse=[new objectForKey:#"HS_GetResponse"];
NSLog(#"Login Response DICT =%#",LoginResponse);
NSDictionary *LoginResult=[LoginResponse objectForKey:#"HS_GetResult"];
NSLog(#"Login Result =%#",LoginResult);
if(LoginResult.count>0)
{
NSLog(#"Login Result = %#",LoginResult);
NSLog(#"Login Result Dict =%#",LoginResult);
NSString *teststr =[[NSString alloc] init];
teststr =[LoginResult objectForKey:#"text"];
NSLog(#"Test String Value =%#",teststr);
NSString *string = [LoginResult valueForKey:#"text"];
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
responseletetudedict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"Latetude Dictionary =%#",responseletetudedict);
idlatetudearray=[[NSMutableArray alloc]init];
idlatetudearray=[responseletetudedict valueForKey:#"City"];
NameHSArray=[[NSMutableArray alloc] init];
NameHSArray=[responseletetudedict valueForKey:#"Name"];
AddressHSArray=[[NSMutableArray alloc] init];
AddressHSArray=[responseletetudedict valueForKey:#"Address"];
FacilitiesHSArray=[[NSMutableArray alloc] init];
FacilitiesHSArray=[responseletetudedict valueForKey:#"Facilities"];
PhoneNoHSArray=[[NSMutableArray alloc] init];
PhoneNoHSArray=[responseletetudedict valueForKey:#"Phoneno"];
FaxnoHSArray=[[NSMutableArray alloc] init];
FaxnoHSArray=[responseletetudedict valueForKey:#"Faxno"];
LatitudeHSArray=[[NSMutableArray alloc] init];
LatitudeHSArray=[responseletetudedict valueForKey:#"Latitude"];
LongitudeHSArray=[[NSMutableArray alloc] init];
LongitudeHSArray=[responseletetudedict valueForKey:#"Longitude"];
TypeHSArray=[[NSMutableArray alloc] init];
TypeHSArray=[responseletetudedict valueForKey:#"Type"];
for (int i=0; i<NameHSArray.count; i++) {
double LatitudeDouble = [LatitudeHSArray[i] doubleValue];
double LongitudeDouble = [LongitudeHSArray[i] doubleValue];
CLLocationCoordinate2D position = CLLocationCoordinate2DMake(LatitudeDouble, LongitudeDouble);
GMSMarker *marker = [GMSMarker markerWithPosition:position];
marker.title = NameHSArray[i];
marker.snippet=AddressHSArray[i];
userData = [[NSArray alloc] initWithObjects:NameHSArray[i], AddressHSArray[i],FacilitiesHSArray[i], PhoneNoHSArray[i],FaxnoHSArray[i], TypeHSArray[i], nil];
marker.userData = userData;
if([TypeHSArray[i] isEqualToString:#"ESIC"])
{
marker.icon = [UIImage imageNamed:#"mapicon2.png"];
}
else
{
marker.icon = [UIImage imageNamed:#"mapicon1.png"];
}
GMSCameraUpdate *zoomCamera = [GMSCameraUpdate zoomIn];
[mapView animateWithCameraUpdate:zoomCamera];
marker.map = mapView;
}
Add in the Image when I click on Nobel Hospital I call the delegate
- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker {
// your click action
StringAddress = marker.snippet;
StringName = marker.title;
NSLog(#"Address=%#",StringAddress);
NSLog(#"Name= %#",StringName);
lblNamepopup.text=StringName;
lblAddresspopup.text=StringAddress;
NSLog(#"User Data Array = %#",userData);
viewpopup.hidden=NO;
viewpopup.transform = CGAffineTransformMakeScale(0.01, 0.01);
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
viewpopup.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished){
// do something once the animation finishes, put it here
}];
}
Hear in this delegate I need to get the current name of string address.But hear I am getting the Last value means the string get override. How can I get the value which I have click from array. Thanks in Advance!
You can get index as follow
-(void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker
{
NSInteger index = [NameHSArray indexOfObject:marker.title];
NSLog(#"%ld",(long)index);
}
--- EDIT ---
You can also use
i found some reference from library.
Note that userData should not hold any strong references to any Maps
objects, otherwise a loop may be created (preventing ARC from releasing
objects).
NOTE :-
You can pass data through snippet but snippet show data into info window. so you creates a custom info window and show data as you want.
like this,
NSArray * userData = [NSArray alloc] initWithObjects:FacilitiesHSArray[i], PhoneNoHSArray[i],FaxnoHSArray[i], nil];
NSString *userDataString = [userData componentsJoinedByString:#";"];
marker.snippet = userDataString;
retrive
like this,
NSString *userDataString = marker.snippet;
NSArray *array = [userDataString componentsSeparatedByString:#";"];
NSLog(#"%#",array);
You can Do Like this
- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker {
// your click action
StringAddress = marker.snippet;
StringName = marker.title;
NSInteger indexCheck = [NameHSArray indexOfObject:marker.title];
NSLog(#"Curret Index =%ld",(long)indexCheck);
StringName=[NSString stringWithFormat:#"%#",[NameHSArray objectAtIndex:indexCheck]];
StringAddress=[NSString stringWithFormat:#"%#",[AddressHSArray objectAtIndex:indexCheck]];
StringPhoneNo=[NSString stringWithFormat:#"%#",[PhoneNoHSArray objectAtIndex:indexCheck]];
NSLog(#"Address=%#",StringAddress);
NSLog(#"Name= %#",StringName);
NSLog(#"Phone No =%#",StringPhoneNo);
lblNamepopup.text=StringName;
lblAddresspopup.text=StringAddress;
}
I got the current location based on the Longitude and Latitude values and then I also got multiple places on google map using Annotation. Now I want to get the longitude and latitude values based on the Address( i.e street,city and county).Need some guidance on how this can be achieved.
Till now, this is what I have tried:-
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize streetField = _streetField, cityField = _cityField, countryField = _countryField, fetchCoordinatesButton = _fetchCoordinatesButton, nameLabel = _nameLabel, coordinatesLabel = _coordinatesLabel;
#synthesize geocoder = _geocoder;
- (void)viewDidLoad
{
[super viewDidLoad];
_streetField.delegate=self;
_cityField.delegate=self;
_countryField.delegate=self;
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)fetchCoordinates:(id)sender {
NSLog(#"Fetch Coordinates");
if (!self.geocoder) {
NSLog(#"Geocdoing");
self.geocoder = [[CLGeocoder alloc] init];
}
NSString *address = [NSString stringWithFormat:#"%# %# %#", self.streetField.text, self.cityField.text, self.countryField.text];
NSLog(#"GET Addres%#",address);
self.fetchCoordinatesButton.enabled = NO;
[self.geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Fetch Gecodingaddress");
if ([placemarks count] > 0) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(#"GET placemark%#",placemark);
CLLocation *location = placemark.location;
NSLog(#"GET location%#",location);
CLLocationCoordinate2D coordinate = location.coordinate;
self.coordinatesLabel.text = [NSString stringWithFormat:#"%f, %f", coordinate.latitude, coordinate.longitude];
NSLog(#"CoordinatesLabel%#",self.coordinatesLabel.text);
if ([placemark.areasOfInterest count] > 0) {
NSString *areaOfInterest = [placemark.areasOfInterest objectAtIndex:0];
self.nameLabel.text = areaOfInterest;
NSLog(#"NameLabe%#",self.nameLabel.text);
}
}
self.fetchCoordinatesButton.enabled = YES;
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
#end
Above code is not working to give me the latitude and longitude.Need some help on what am I doing wrong here or if I am missing on something.
Thanks in Advance.
This was very old answer, Kindly check with new Updates
EDIT:
Before using this check with iOS8 updation
NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription
This is for getting lat and long based user area like street name,state name,country.
-(CLLocationCoordinate2D) getLocationFromAddressString: (NSString*) addressStr {
double latitude = 0, longitude = 0;
NSString *esc_addr = [addressStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *req = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%#", esc_addr];
NSString *result = [NSString stringWithContentsOfURL:[NSURL URLWithString:req] encoding:NSUTF8StringEncoding error:NULL];
if (result) {
NSScanner *scanner = [NSScanner scannerWithString:result];
if ([scanner scanUpToString:#"\"lat\" :" intoString:nil] && [scanner scanString:#"\"lat\" :" intoString:nil]) {
[scanner scanDouble:&latitude];
if ([scanner scanUpToString:#"\"lng\" :" intoString:nil] && [scanner scanString:#"\"lng\" :" intoString:nil]) {
[scanner scanDouble:&longitude];
}
}
}
CLLocationCoordinate2D center;
center.latitude=latitude;
center.longitude = longitude;
NSLog(#"View Controller get Location Logitute : %f",center.latitude);
NSLog(#"View Controller get Location Latitute : %f",center.longitude);
return center;
}
call the method like this in viewdidload method or somewhere according to your project
[self getLocationFromAddressString:#"chennai"];
just pass this in your browser
http://maps.google.com/maps/api/geocode/json?sensor=false&address=chennai
and you will have json format with lat and lon
http://maps.google.com/maps/api/geocode/json?sensor=false&address=#"your city name here"
NSString *address = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%# %# %#", self.streetField.text, self.cityField.text, self.countryField.text];
the usage of this method....
CLLocationCoordinate2D center;
center=[self getLocationFromAddressString:#"uthangarai"];
double latFrom=¢er.latitude;
double lonFrom=¢er.longitude;
NSLog(#"View Controller get Location Logitute : %f",latFrom);
NSLog(#"View Controller get Location Latitute : %f",lonFrom);
Someone looking for Swift 2.0 solution can use below :
let address = "1 Infinite Loop, CA, USA"
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(address, completionHandler: {(placemarks, error) -> Void in
if((error) != nil){
print("Error", error)
}
if let placemark = placemarks?.first {
let coordinates:CLLocationCoordinate2D = placemark.location!.coordinate
coordinates.latitude
coordinates.longitude
print("lat", coordinates.latitude)
print("long", coordinates.longitude)
}
})
Try this,
NSString *address = [NSString stringWithFormat:#"%#,%#,%#", self.streetField.text, self.cityField.text,self.countryField.text];
[self.geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error)
{
if(!error)
{
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(#"%f",placemark.location.coordinate.latitude);
NSLog(#"%f",placemark.location.coordinate.longitude);
NSLog(#"%#",[NSString stringWithFormat:#"%#",[placemark description]]);
}
else
{
NSLog(#"There was a forward geocoding error\n%#",[error localizedDescription]);
}
}
];
Swift
public func getLocationFromAddress(address : String) -> CLLocationCoordinate2D {
var lat : Double = 0.0
var lon : Double = 0.0
do {
let url = String(format: "https://maps.google.com/maps/api/geocode/json?sensor=false&address=%#", (address.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!))
let result = try Data(contentsOf: URL(string: url)!)
let json = JSON(data: result)
lat = json["results"][0]["geometry"]["location"]["lat"].doubleValue
lon = json["results"][0]["geometry"]["location"]["lng"].doubleValue
}
catch let error{
print(error)
}
return CLLocationCoordinate2D(latitude: lat, longitude: lon)
}
I used SwiftyJSON but you can parse the JSON response however you want
- (IBAction)forwardButton:(id)sender
{
if([self.address.text length])
{
NSString *place = self.address.text;
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
__unsafe_unretained RTGeoCoderViewController *weakSelf = self;
[geocoder geocodeAddressString:place completionHandler:^(NSArray* placemarks, NSError* error)
{
NSLog(#"completed");
if ( error )
{
NSLog(#"error = %#", error );
dispatch_async(dispatch_get_main_queue(),
^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[self errorMessage:error.code] delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
});
}
else
{
NSLog(#"%#",placemarks);
}
}];
}
}
Try this
- (void)getAddressFromAdrress:(NSString *)address withCompletationHandle:(void (^)(NSDictionary *))completationHandler {
CLGeocoder *geoCoder = [[CLGeocoder alloc] init];
//Get the address through geoCoder
[geoCoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
if ([placemarks count] > 0 && !error) {
//get the address from placemark
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
_latitudeUserLocation = coordinate.latitude;
_longitudeUserLocation = coordinate.longitude;
NSString *postalCode = placemark.addressDictionary[(NSString*)kABPersonAddressZIPKey];
if (postalCode == nil) postalCode = #"";
if (locatedAt == nil) locatedAt = #"";
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
postalCode ,kPostalCode,
locatedAt ,kFullAddress,
nil];
completationHandler(dictionary);
} else {
completationHandler(nil);
}
}];
}
I am using Google Maps SDK in iOS app.I am stuck at plotting multiple pins on map.This is how I am trying to plot the pins.And I used the exact same approach to show multiple pins using MapKit which worked fine.But no success with google Maps.
-(void)plotMembersOnMap
{
for (NSMutableDictionary *obj in self.jsonDictionary)
{
membersDict = [obj objectForKey:#"members"];
NSLog(#"Count member %d",[membersDict count]); // shows count
for (NSDictionary *obj in membersDict)
{
CLLocationCoordinate2D center;
NSString *latitudeString = [obj objectForKey:#"lat"];
NSString *longitudeString = [obj objectForKey:#"lng"];
double latitude = [latitudeString doubleValue];
double longitude = [longitudeString doubleValue];
center.latitude =latitude;
center.longitude = longitude;
NSString *userName = [obj objectForKey:#"pseudo"];
GMSMarker *marker = [[GMSMarker alloc] init];
marker.map = mapView_;
marker.position = CLLocationCoordinate2DMake(center.latitude, center.longitude);
customGoogleCallout.callOutTitleLabel.text = #"Member";
customGoogleCallout.callOutUserName.text = userName;
marker.icon = [UIImage imageNamed:#"marker_membre.png"];
}
}
}
just try to add lat and lon to an array then supply the marker.position.
have some loop for i and position is object at index[i].
this might help...
CLLocationCoordinate2D center = { [[obj objectForKey:#"lat"] floatValue] , [[obj objectForKey:#"lon"] floatValue] };
GMSMarker *marker = [GMSMarker markerWithPosition:center];
Try this ,
NSArray *latitudeString = [obj objectForKey:#"lat"];
NSArray *longitudeString = [obj objectForKey:#"lng"];
Instead of
NSString *latitudeString = [obj objectForKey:#"lat"];
NSString *longitudeString = [obj objectForKey:#"lng"];
Maybe because it's plotting the latest coordinate you assign to center. You should make new instance so the previous value will not replaced.
I am trying to parse a JSON from Google to place annotations on Map. Parsing JSON using AFNetworking and parsing process is in Singleton class. I am getting values from two different JSON.
Places Autocomplete JSON of Google
Places Details JSON of Google
Here is my code for Singleton class
-(void)getData:(NSString *)searchString
{
_dataArray = [[NSMutableArray alloc]init];
NSString *requestString = [[NSString alloc]init];
requestString = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%#&sensor=true&key=APIKEY",searchString];
requestString = [requestString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *URL = [NSURL URLWithString:requestString];
NSURLRequest *requestURL = [NSURLRequest requestWithURL:URL];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:requestURL success:^(NSURLRequest *requestURL,NSHTTPURLResponse *response, id JSON){
self.dataArray = [JSON objectForKey:#"predictions"];
[[NSNotificationCenter defaultCenter]postNotificationName:#"Doreload" object:nil];
}failure:^(NSURLRequest *requestURL,NSHTTPURLResponse *response,NSError *error, id JSON){
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
}
-(void)detailList:(NSString *)referenceString
{
_detailArray = [[NSMutableArray alloc]init];
NSString *requestString = [[NSString alloc]initWithFormat:#"https://maps.googleapis.com/maps/api/place/details/json?reference=%#&sensor=true&key=APIKEY",referenceString];
NSURL *URL = [NSURL URLWithString:requestString];
NSURLRequest *requestURL = [NSURLRequest requestWithURL:URL];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:requestURL success:^(NSURLRequest *requestURL,NSHTTPURLResponse *response, id JSON){
self.detailArray = [JSON objectForKey:#"result"];
[[NSNotificationCenter defaultCenter]postNotificationName:#"showList" object:nil];
}failure:^(NSURLRequest *requestURL,NSHTTPURLResponse *response,NSError *error, id JSON){
}];
[operation start];
}
In ViewController with the first function I am passing the name of the Place in the tableView :
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
sharedRequest = [RequestHandler sharedRquest];
static NSString *cellID = #"Cell Identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.textLabel.text = [[sharedRequest.dataArray objectAtIndex:indexPath.row]objectForKey:#"description"];
[_spinner stopAnimating];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *details = [[DetailViewController alloc]initWithNibName:#"DetailViewController" bundle:nil];
details.stringReference = [[sharedRequest.dataArray objectAtIndex:indexPath.row]objectForKey:#"reference"];
[self.navigationController pushViewController:details animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
And the Details Class is :
- (void)viewDidLoad
{
[super viewDidLoad];
[[RequestHandler sharedRquest]detailList:self.stringReference];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(showOnMap) name:#"showList" object:nil];
self.spinner = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
self.spinner.hidesWhenStopped = YES;
self.spinner.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:_spinner];
[_spinner startAnimating];
self.mapView.showsUserLocation = TRUE;
self.mapView.delegate = self;
}
- (void)showOnMap:(NSNotification *)notification
{
NSLog(#"Entered");
sharedRequest = [RequestHandler sharedRquest];
NSString *string = [[NSString alloc]init];
string = [sharedRequest.detailArray valueForKey:#"name"];
self.label.text = string;
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
sharedRequest = [RequestHandler sharedRquest];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 30000, 30000);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
double latitude = [[[[sharedRequest.detailArray valueForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lat"]doubleValue];
double longitude =[[[[sharedRequest.detailArray valueForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lng"]doubleValue];
CLLocationCoordinate2D coord = { latitude, longitude };
MKPointAnnotation *point = [[MKPointAnnotation alloc]init];
point.coordinate = coord;
point.title = [sharedRequest.detailArray valueForKey:#"name"];
[self.mapView addAnnotation:point];
[_spinner stopAnimating];
}
The problem is in Details Class for the first time when using with break points it shows annotations and second it throughs an error:
-[__NSArrayI objectForKey:]: unrecognized selector sent to instance 0x86332e0
EDIT:
here is what shared.detailArray has:
"address_components" = (
{
"long_name" = Francestown;
"short_name" = Francestown;
types = (
locality,
political
);
},
{
"long_name" = Hillsborough;
"short_name" = Hillsborough;
types = (
"administrative_area_level_2",
political
);
},
{
"long_name" = "New Hampshire";
"short_name" = NH;
types = (
"administrative_area_level_1",
political
);
},
{
"long_name" = "United States";
"short_name" = US;
types = (
country,
political
);
}
);
"adr_address" = "<span class=\"locality\">Francestown</span>, <span class=\"region\">NH</span>, <span class=\"country-name\">USA</span>";
"formatted_address" = "Francestown, NH, USA";
geometry = {
location = {
lat = "42.9875";
lng = "-71.8130599";
};
viewport = {
northeast = {
lat = "43.03844";
lng = "-71.7474139";
};
southwest = {
lat = "42.949703";
lng = "-71.88583609999999";
};
};
};
icon = "http://maps.gstatic.com/mapfiles/place_api/icons/geocode-71.png";
id = ccd239475516163d29405af62fb286bedb4c6377;
name = Francestown;
reference = "CoQBcwAAAPSQxzNrepzPywLZr1PDoPEmQmGR8rIPTPoQ_f2kXpceRGHU_J_FEcrDxZSzebqLRpNYlUC_-xRJVV7Jx_mW1KJ33foU9y0ZCNK_kC1orqZVK5B-EONPD_Ef_e9WXXZdfOZTBQzNYLhoVdP8Ufa1bPe_vuuwe3rqYtf80IyANb8mEhCKi6kISip4ItpBFfgWjuGvGhSj0hURZaTQXX4lnFlxe2v4O5Uo6Q";
types = (
locality,
political
);
url = "https://maps.google.com/maps/place?q=Francestown&ftid=0x89e22c36ba6dc937:0x52cccc5f0f9b8663";
vicinity = Francestown;
}
I tried a lot to understand the error, but all in vain.
Any help would be appreciable.
Thanks
Hope this will help you if you are looking to achieve results using a different way.
I used NSJSONSerialization class to parse the json response from Google.
In this method I parse the NSMutable Data object- _routeData(created by appending data from Google response)
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSMutableArray *polyLinesArray = [[NSMutableArray alloc] init];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:_routeData options:kNilOptions error:nil];
NSArray *locationArray = [[[[[jsonDict valueForKey:#"routes"]valueForKey:#"legs"]valueForKey:#"steps"]valueForKey:#"polyline"] valueForKey:#"points"];
if(locationArray.count > 0)
{
NSArray *polyLinePointsArray = [[locationArray objectAtIndex:0]objectAtIndex:0];
for (int i = 0; i < [polyLinePointsArray count]; i++)
{
NSString *encodedPoints = [polyLinePointsArray objectAtIndex:i];
MKPolyline *route = [self polylineWithEncodedString:encodedPoints];
[polyLinesArray addObject:route];
}
// remove previous overlays
if(_mapView.overlays.count > 0)
{
[_mapView removeOverlays:_mapView.overlays];
}
[self.mapView addOverlays:polyLinesArray];
}
}
To decode the polyline points response from Google I used a class I found on stackoverflow..
- (MKPolyline *)polylineWithEncodedString:(NSString *)encodedString
{
const char *bytes = [encodedString UTF8String];
NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger idx = 0;
NSUInteger count = length / 4;
CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
NSUInteger coordIdx = 0;
float latitude = 0;
float longitude = 0;
while (idx < length) {
char byte = 0;
int res = 0;
char shift = 0;
do {
byte = bytes[idx++] - 63;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
latitude += deltaLat;
shift = 0;
res = 0;
do {
byte = bytes[idx++] - 0x3F;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
longitude += deltaLon;
float finalLat = latitude * 1E-5;
float finalLon = longitude * 1E-5;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
coords[coordIdx++] = coord;
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:coordIdx];
free(coords);
return polyline;
}
Instead of this
double latitude = [[[[sharedRequest.detailArray valueForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lat"]doubleValue];
double longitude =[[[[sharedRequest.detailArray valueForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lng"]doubleValue];
try this,
double latitude = [[[[sharedRequest.detailArray valueForKey:#"geometry"]valueForKey:#"location"]valueForKey:#"lat"]doubleValue];
double longitude =[[[[sharedRequest.detailArray valueForKey:#"geometry"]valueForKey:#"location"]valueForKey:#"lng"]doubleValue];
Found the Solution:
- (void)showOnMap:(NSNotification *)notification
{
NSLog(#"Entered");
sharedRequest = [RequestHandler sharedRquest];
NSString *string = [[NSString alloc]init];
string = [sharedRequest.detailArray valueForKey:#"name"];
self.label.text = string;
double latitude = [[[[sharedRequest.detailArray valueForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lat"]doubleValue];
double longitude =[[[[sharedRequest.detailArray valueForKey:#"geometry"]objectForKey:#"location"]objectForKey:#"lng"]doubleValue];
CLLocationCoordinate2D coord = { latitude, longitude };
MKPointAnnotation *point = [[MKPointAnnotation alloc]init];
point.coordinate = coord;
point.title = [sharedRequest.detailArray valueForKey:#"name"];
[self.mapView addAnnotation:point];
[_spinner stopAnimating];
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
sharedRequest = [RequestHandler sharedRquest];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 30000, 30000);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
}
I'm using mapKit to draw a route from point to point. I did it.
But i want to get route length NOT the distance as straight line.
nextView.startPoint = [NSString stringWithFormat:#"%f,%f", userLatitude , userLongitude];
nextView.endPoint = [NSString stringWithFormat:#"%f,%f", 30.793636, 31.009641];
[diretions loadWithStartPoint:startPoint endPoint:endPoint options:options];
Aloso i want to give it a mid point to path through.
To do that you are going to have to use a directions API, preferably Google Directions API. You should look at that link and read it through, Apple does not have a built in direction API. You can send it a request and ask for JSON response, I would use AFNetworking to make like easier (on Github) and JSONKit also on Github for that. Then send a request and parse the JSON response. In the response you need the encoded points, which is a set of many coordinates that basically traces the route. You would then need to display that on an overlay. Here is some sample code, but before you copy and paste this in make sure you read the GDirections API Site, you will understand everything MUCH easier and can learn how to do more:
// DRAG IN AFNETWORKING FILES AND JSON KIT FILES TO YOUR PROJECT AND ALSO IMPORT THE MAP KIT AND CORE LOCATION FRAMEWORKS
// IMPORT FILES
#import "StringHelper.h"
#import "JSONKit.h"
#import "AFJSONRequestOperation.h"
#import "AFHTTPClient.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
// DECLARE MUTABLE ARRAY IN .H:
NSMutableArray *_path;
// ADD THIS CODE TO WHEN YOU WANT TO REQUEST FOR DIRECTIONS
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];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { }];
[_httpClient enqueueHTTPRequestOperation:operation];
// NOW ADD THE PARSERESPONSE METHOD
- (void)parseResponse:(NSDictionary *)response {
NSString *status = [response objectForKey: #"status"];
NSArray *routes = [response objectForKey:#"routes"];
NSDictionary *routePath = [routes lastObject];
if (routePath) {
NSString *overviewPolyline = [[routePath objectForKey: #"overview_polyline"] objectForKey:#"points"];
_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];
}
}
// IMPLEMENTING THE DECODEPOLYLINE METHOD:
-(NSMutableArray *)decodePolyLine:(NSString *)encodedStr {
NSMutableString *encoded = [[NSMutableString alloc] initWithCapacity:[encodedStr length]];
[encoded appendString:encodedStr];
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
CLLocation *location = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:location];
}
return array;
}
// IMPLEMENTING THE VIEWFOROVERLAY DELEGATE METHOD (MAKE SURE TO SET YOUR MAP VIEW'S DELEGATE TO SELF OR THIS WONT GET CALLED)
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor blueColor];
polylineView.lineWidth = 5.0;
polylineView.alpha = 0.7;
return polylineView;
}
And that should get your directional routes up and running!