-(IBAction)SendTextTapped:(id)sender{
if ([MFMessageComposeViewController canSendText]) {
MFMessageComposeViewController* messageController = [[MFMessageComposeViewController alloc] init];
messageController.messageComposeDelegate = self;
__block NSString *fullA = [[NSString alloc] init];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *newerLocation = [[CLLocation alloc]initWithLatitude:21.1700
longitude:72.8300];
[geocoder reverseGeocodeLocation:newerLocation
completionHandler:^(NSArray *placemarks, NSError *error) {
if (error) {
NSLog(#"Geocode failed with error: %#", error);
return;
}
if (placemarks && placemarks.count > 0)
{
CLPlacemark *placemark = placemarks[0];
NSDictionary *addressDictionary =
placemark.addressDictionary;
NSLog(#"%# ", addressDictionary);
NSString *address = [addressDictionary
objectForKey:(NSString *)kABPersonAddressStreetKey];
NSString *city = [addressDictionary
objectForKey:(NSString *)kABPersonAddressCityKey];
NSString *state = [addressDictionary
objectForKey:(NSString *)kABPersonAddressStateKey];
NSString *zip = [addressDictionary
objectForKey:(NSString *)kABPersonAddressZIPKey];
NSLog(#"%# %# %# %#", address,city, state, zip);
//NSLog(fullA);
fullA=(#"%# %# %# %#", address,city, state, zip);
}
}];
[messageController setBody:fullA];
[self presentModalViewController:messageController animated:YES];
}
else {
NSLog(#"%#" , #"Sorry, you need to setup mail first!");
}
}
I have attempted using __block, or everything I could find in online tutorials.
This does print out the full address in NSLog. However, no matter what I have tried this does not show up for [messageController setBody:(#"%# %# %# %#",city, state, address, zip)];
and using (setBody:#"Hello") works just fine...
I'm sure there is something small that I can do to fix this, but everything I have tried has failed. Any ideas would be great!
You can't do what you are doing the way you are doing it. The call to reverseGeocodeLocation is asynchronous. You end up presenting the message controller long before you get back the address information. This is why the body is always empty.
You need to modify the code to create and display the message composer from within the completion handler (but you must dispatch the code on the main queue).
- (IBAction)SendTextTapped:(id)sender{
if ([MFMessageComposeViewController canSendText]) {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *newerLocation = [[CLLocation alloc]initWithLatitude:21.1700 longitude:72.8300];
[geocoder reverseGeocodeLocation:newerLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (error) {
NSLog(#"Geocode failed with error: %#", error);
return;
}
NSString *body = #"";
if (placemarks && placemarks.count > 0) {
CLPlacemark *placemark = placemarks[0];
NSDictionary *addressDictionary =
placemark.addressDictionary;
NSLog(#"%# ", addressDictionary);
NSString *address = [addressDictionary
objectForKey:(NSString *)kABPersonAddressStreetKey];
NSString *city = [addressDictionary
objectForKey:(NSString *)kABPersonAddressCityKey];
NSString *state = [addressDictionary
objectForKey:(NSString *)kABPersonAddressStateKey];
NSString *zip = [addressDictionary
objectForKey:(NSString *)kABPersonAddressZIPKey];
NSLog(#"%# %# %# %#", address,city, state, zip);
//NSLog(fullA);
body = [NSString stringWithFormat:#"%# %# %# %#", address,city, state, zip];
}
dispatch_async(dispatch_get_main_queue(), ^{
MFMessageComposeViewController* messageController = [[MFMessageComposeViewController alloc] init];
messageController.messageComposeDelegate = self;
[messageController setBody:body];
[self presentModalViewController:messageController animated:YES];
});
}];
} else {
NSLog(#"%#" , #"Sorry, you need to setup mail first!");
}
}
Use stringWithFormat in order to set body with different objects, something like this
[messageController setBody:[NSString stringWithFormat:#"%# %# %# %#",city, state, address, zip];
Related
I'm trying to convert my lat long into address using method:
#pragma mark:convert latLong to address
-(void)getMerchantAddress:(NSDictionary *)dict
{
double lata = [[dict valueForKey:#"user_lat"] doubleValue];
double longa = [[dict valueForKey:#"user_long"] doubleValue];
NSLog(#"%f",lata);
NSLog(#"%f",longa);
CLLocation *LocationAtual = [[CLLocation alloc]initWithLatitude:lata longitude:longa];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:LocationAtual completionHandler:^(NSArray *placemarks, NSError *error)
{
if(placemarks && placemarks.count > 0)
{
CLPlacemark *placemark= [placemarks objectAtIndex:0];
NSArray *lines = placemark.addressDictionary[ #"FormattedAddressLines"];
NSString *addressString = [lines componentsJoinedByString:#","];
_usrtAddressLbl.text = addressString;
_userAddressLbl.text = addressString;
}
}];
}
my app crash # point
[geocoder reverseGeocodeLocation:LocationAtual completionHandler:^(NSArray *placemarks, NSError *error)
Error showing:
[__NSCFNumber rangeOfCharacterFromSet:]: unrecognized selector sent to instance 0xb000000000005f53
How can I resolve it. Thanks in advance.
Try this its working for me
-(void)getMerchantAddress:(NSDictionary *)dict
{
float lata = [[dict objectForKey:#"user_lat"] floatValue];
float longa = [[dict objectForKey:#"user_long"] floatValue];
CLGeocoder *ceo = [[CLGeocoder alloc]init];
CLLocation *loc = [[CLLocation alloc]initWithLatitude:lata longitude:longa]; //insert your coordinates
[ceo reverseGeocodeLocation:loc
completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
if (placemark) {
NSLog(#"placemark %#",placemark);
//String to hold address
strAddress = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
NSLog(#"addressDictionary %#", placemark.addressDictionary);
}else {
}
}
];
}
I am accessing contact from user phone. Everything is working perfectly but when I add it into the NSMutableArray then nothing is entered. In breakpoint when I click on array its showing 0X16bed870. My code is as follow.
-(void)mycontact
{
NSMutableArray * contactNumbersArray = [[NSMutableArray alloc] init];
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
if (status == CNAuthorizationStatusDenied || status == CNAuthorizationStatusRestricted)
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:#"This app previously was refused permissions to contacts; Please go to settings and grant permission to this app so it can use contacts" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:TRUE completion:nil];
return;
}
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted == YES) {
//keys with fetching properties
NSArray *keys = #[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPhoneNumbersKey, CNContactImageDataKey];
NSString *containerId = store.defaultContainerIdentifier;
NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:containerId];
NSError *error;
NSArray *cnContacts = [store unifiedContactsMatchingPredicate:predicate keysToFetch:keys error:&error];
if (error) {
NSLog(#"error fetching contacts %#", error);
} else {
NSString *phone;
NSString *fullName;
NSString *firstName;
NSString *lastName;
UIImage *profileImage;
for (CNContact *contact in cnContacts) {
// copy data to my custom Contacts class.
firstName = contact.givenName;
lastName = contact.familyName;
if (lastName == nil) {
fullName=[NSString stringWithFormat:#"%#",firstName];
} else if (firstName == nil) {
fullName=[NSString stringWithFormat:#"%#",lastName];
} else {
fullName=[NSString stringWithFormat:#"%# %#",firstName,lastName];
}
UIImage *image = [UIImage imageWithData:contact.imageData];
if (image != nil) {
profileImage = image;
}else{
profileImage = [UIImage imageNamed:#"person-icon.png"];
}
for (CNLabeledValue *label in contact.phoneNumbers) {
phone = [label.value stringValue];
if ([phone length] > 0) {
[contactNumbersArray addObject:phone];
}
}
NSDictionary* personDict = [[NSDictionary alloc] initWithObjectsAndKeys: fullName,#"fullName",profileImage,#"userImage",phone,#"PhoneNumbers", nil];
}
dispatch_async(dispatch_get_main_queue(), ^{
for(int j=0;j<[contactNumbersArray count];j++)
{
NSString *newString = [[contactNumbersArray[j] componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:#""];
contactNumbersArray[j]=newString;
}
});
}
}
}];
}
I'm trying to get the postal code when my map region has changed by using CLGeocoder:
CLLocation *location = [[CLLocation alloc] initWithLatitude:13.184098 longitude:77.725978];
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
CLLocation *location=[[CLLocation alloc] initWithLatitude:13.184098 longitude:77.725978];
[self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error)
{
if (!(error))
{
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(#"placemark %#",placemark);
NSString *Zipcode = [[NSString alloc]initWithString:placemark.postalCode];
NSLog(#"%#",Zipcode);
}
else
{
NSLog(#"Geocode failed with error %#", error); // Error handling must required
}
}];
}
i am getting response like this
{ Country = India; CountryCode = IN; FormattedAddressLines = ( Amarwara, "Madhya Pradesh", India ); Name = Amarwara; State = "Madhya Pradesh"; SubAdministrativeArea = Chhindwara; SubLocality = Amarwara; }
I'm able to get the postal code for the first time. When the region changes, I try to reverse geocode the postal code. I even tried setting the location explicitly (line 1) and it's still returning null postal code. Can any one help this strange bug?
Try this
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *newLocation = [[CLLocation alloc]initWithLatitude:21.1700
longitude:72.8300];
[geocoder reverseGeocodeLocation:newLocation
completionHandler:^(NSArray *placemarks, NSError *error) {
if (error) {
NSLog(#"Geocode failed with error: %#", error);
return;
}
if (placemarks && placemarks.count > 0)
{
CLPlacemark *placemark = placemarks[0];
NSDictionary *addressDictionary =
placemark.addressDictionary;
NSLog(#"%# ", addressDictionary);
NSString *address = [addressDictionary
objectForKey:(NSString *)kABPersonAddressStreetKey];
NSString *city = [addressDictionary
objectForKey:(NSString *)kABPersonAddressCityKey];
NSString *state = [addressDictionary
objectForKey:(NSString *)kABPersonAddressStateKey];
NSString *zip = [addressDictionary
objectForKey:(NSString *)kABPersonAddressZIPKey];
NSLog(#"%# %# %# %#", address,city, state, zip);
}
}];
Here's a piece of sample code:
[_geoCoder reverseGeocodeLocation:self.locationManager.location // You can pass aLocation here instead
completionHandler:^(NSArray *placemarks, NSError *error) {
dispatch_async(dispatch_get_main_queue(),^ {
// do stuff with placemarks on the main thread
if (placemarks.count == 1) {
CLPlacemark *place = [placemarks objectAtIndex:0];
// NSLog([place postalCode]);
NSString* addressString1 = [place thoroughfare];
addressString1 = [addressString1 stringByAppendingString:[NSString stringWithFormat:#"%#",[place.addressDictionary objectForKey:(NSString*)kABPersonAddressZIPKey]]];//
NSLog(#"%#",addressString1);// is null ??
NSlog(#"%#",place.postalCode);//is null ??
//[self performSelectorInBackground:#selector(log) withObject:nil];
}
});
}];
I guess you probably only had a 'bad' coordinate, where no zip code exists. Try the following snippet. It should display various information and the zip code '80802' at the end:
CLLocationCoordinate2D myCoordinates = { 48.167222, 11.586111 };
CLLocation *location = [[CLLocation alloc]initWithLatitude:myCoordinates.latitude longitude:myCoordinates.longitude];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"%d Placemarks %#", placemarks.count, placemarks);
CLPlacemark *place = [placemarks objectAtIndex:0];
NSLog(#"Placemark %#", place);
NSLog(#"Address Dictionary: %#", place.addressDictionary);
NSLog(#"Zip key %#", [place.addressDictionary objectForKey:(NSString *)kABPersonAddressZIPKey]);
}];
Insert different coordinates in the first line and experiment yourself.
I saw from another question here : Determine iPhone user's country that it is possible to get the current country the user of the iPhone is in.
And that is quite convenient for many uses. However, would it be possible to go even deeper and infer from iOS (if it has the information) which state or city the user is in as well?
I suppose reverse geocoding services would be the next step if things weren't possible.. Are there even such things as a reverse geocoding service you can hire for your app though?
MKReverseGeocoder is deprecated in iOS 5, now it's CLGeocoder
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[self.locationManager stopUpdatingLocation];
CLGeocoder * geoCoder = [[CLGeocoder alloc] init];
[geoCoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
for (CLPlacemark * placemark in placemarks) {
.... = [placemark locality];
}
}];
}
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *newLocation = [[CLLocation alloc]initWithLatitude:21.1700
longitude:72.8300];
[geocoder reverseGeocodeLocation:newLocation
completionHandler:^(NSArray *placemarks, NSError *error) {
if (error) {
NSLog(#"Geocode failed with error: %#", error);
return;
}
if (placemarks && placemarks.count > 0)
{
CLPlacemark *placemark = placemarks[0];
NSDictionary *addressDictionary =
placemark.addressDictionary;
NSLog(#"%# ", addressDictionary);
NSString *address = [addressDictionary
objectForKey:(NSString *)kABPersonAddressStreetKey];
NSString *city = [addressDictionary
objectForKey:(NSString *)kABPersonAddressCityKey];
NSString *state = [addressDictionary
objectForKey:(NSString *)kABPersonAddressStateKey];
NSString *zip = [addressDictionary
objectForKey:(NSString *)kABPersonAddressZIPKey];
NSLog(#"%# %# %# %#", address,city, state, zip);
}
}];
Result
{
City = Surat;
Country = India;
CountryCode = IN;
FormattedAddressLines = (
Surat,
Gujarat,
India
);
Name = Surat;
State = Gujarat;
}
2012-12-20 21:33:26.284 CurAddress[4110:11603] (null) Surat Gujarat (null)
I would start with the CLReverseGeocoder class.
This stackoverflow question gets the current city and can probably be adapted for your use.
Following codes can be easy to retrieve full-details.
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if(placemarks.count){
placeNameLabel.text = [placemarks[0] name];
streetNumberLabel.text = [placemarks[0] subThoroughfare];
streetLabel.text = [placemarks[0] thoroughfare];
neighborhoodLabel.text = [placemarks[0] subLocality];
cityLabel.text = [placemarks[0] locality];
countyLabel.text = [placemarks[0] subAdministrativeArea];
stateLabel.text = [placemarks[0] administrativeArea]; //or province
zipCodeLabel.text = [placemarks[0] postalCode];
countryLabel.text = [placemarks[0] country];
countryCodeLabel.text = [placemarks[0] ISOcountryCode];
inlandWaterLabel.text = [placemarks[0] inlandWater];
oceanLabel.text = [placemarks[0] ocean];
areasOfInterestLabel.text = [placemarks[0] areasOfInterest[0]];
}
}];