Objective-C get variable out of block - ios

I'm struggling with getting a variable out of a block. Seems to be a pretty basic thing but I can't figure it out! How can I access it? e.g. usercity out of the block? Usercity is declared as NSString in .h.
[ceo reverseGeocodeLocation: loc completionHandler:
^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//NSLog(#"placemark %#",placemark);
//String to hold address
//NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
//NSLog(#"addressDictionary %#", placemark.addressDictionary);
//NSLog(#"placemark %#",placemark.region);
NSLog(#"Land %#",placemark.country); // Give Country Name
NSLog(#"City %#",placemark.locality); // Extract the city name
NSLog(#"Adresse %#",placemark.name);
//NSLog(#"location %#",placemark.ocean);
NSLog(#"Zip %#",placemark.postalCode); //ZipCode
NSLog(#"sonstiges %#",placemark.subLocality);
//Save values in variables
usercountry = placemark.country;
usercity = placemark.locality;
userzip = placemark.postalCode;
NSLog(#"usercity: %#",usercity);
//NSLog(#"location %#",placemark.location);
}
];

Is this what you're looking for?
__block NSString *userCity;
[ceo reverseGeocodeLocation: loc completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
...
userCity = placemark.locality;
}];
But if you want to actually be able to check its value outside of the block, you'll have to do so after the completion handler updates the value. Perhaps make it a property, ie. self.userCity?

Your code in the block has to store usercity where you want it. You can't "get something out" of a block, the code in the block has to do it.
You do know that a block can access all variables in the surrounding method, don't you?

Related

Address/Zip Code as NSString to CLLocation

Is there a way to convert a zip code a user enters into a textbox and convert it into a CLLocation? I am trying to compare distance between their current location and either an address or zip code and this would be easy if I can make a CLLocation out of the NSString.
the procedure called geocoding, and that is how it looks if you implement it:
NString *_address = // any address or postcode
CLGeocoder *_geocoder = [[CLGeocoder alloc] init];
[_geocoder geocodeAddressString:_address completionHandler:^(NSArray *placemarks, NSError *error) {
if (placemarks.count > 0) {
CLPlacemark *_placemark = [placemarks firstObject];
CLLocation *_location = _placemark.location;
// ... do whaterver you want to do with the location
}
}];
NOTE: the CoreLocation.framework has to be added to your project properly. you may need to handle errors in your final completion-block, I have not added such part to my code above.

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.

Insert Latitude and Longitude Programmatically for Reverse Geolocation

I have a Situation ,where i am pulling the Latitude and Longitude from a XML file ,Parsing and Displaying it .and i am successfully be able to Do it in Two Different UILabels .but now i need to the Location and Display it in a Label.Can someone suggest me how to achieve that , i have this code , but its only let me to select the Value of Coordinates from Simulator only .
- (IBAction)geoCodeLocation:(id)sender{
//Geocoding Block
[self.geoCoder reverseGeocodeLocation: locationManager.location completionHandler:
^(NSArray *placemarks, NSError *error) {
//Get nearby address
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//String to hold address
NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
//Print the location to console
NSLog(#"I am currently at %#",locatedAt);
//Set the label text to current location
[locationLabel setText:locatedAt];
}];
}
Suggestion : this Question is not about XML parsing .
Try This
CLLocation *location = [[CLLocation alloc] initWithLatitude:37.78583400 longitude:-122.40641700];
[self.geoCoder reverseGeocodeLocation: location completionHandler:
^(NSArray *placemarks, NSError *error) {
//Get nearby address
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//String to hold address
locatedAtcountry = placemark.country;
locatedAtcity = placemark.locality;
locatedAtisocountry = placemark.ISOcountryCode;
//Print the location to console
NSLog(#"Estas en %#",locatedAtcountry);
NSLog(#"Estas en %#",locatedAtcity);
NSLog(#"Estas en %#",locatedAtisocountry);
[cityLabel setText:[NSString stringWithFormat:#"%#",locatedAtcity]];
[locationLabel setText:[NSString stringWithFormat:#"%#",locatedAtcountry]];
//Set the label text to current location
//[locationLabel setText:locatedAt];
}];

Get current city and country from CLGeocoder?

I've been all over the internet trying to find out how to get the city and country from CLGeocoder. I can get the longitude and latitude easily but I need the city and country information, and I keep running into deprecated methods and such, any ideas? It basically needs to get the location, then have an NSString for the country, and an NSString for the city, so I can use them to look up more info or put them on labels, etc.
You need to revise your terminology a bit - CLGeocoder (and most geocoders) won't give you a 'city' per-se - it uses terms such as 'Administrative Area', 'Subadministrative Area', etc. The CLGeocoder object will return an array of CLPlacemark objects which you can then query for the information you need. You init a CLGeocoder and call the reverseGeocodeLocation function with a location and a completion block. Here's an example:
if (osVersion() >= 5.0){
CLGeocoder *reverseGeocoder = [[CLGeocoder alloc] init];
[reverseGeocoder reverseGeocodeLocation:self.currentLocation completionHandler:^(NSArray *placemarks, NSError *error)
{
DDLogVerbose(#"reverseGeocodeLocation:completionHandler: Completion Handler called!");
if (error){
DDLogError(#"Geocode failed with error: %#", error);
return;
}
DDLogVerbose(#"Received placemarks: %#", placemarks);
CLPlacemark *myPlacemark = [placemarks objectAtIndex:0];
NSString *countryCode = myPlacemark.ISOcountryCode;
NSString *countryName = myPlacemark.country;
DDLogVerbose(#"My country code: %# and countryName: %#", countryCode, countryName);
}];
}
Now note that the CLPlacemark doesn't have a 'city' property. The full list of properties can be found here: CLPlacemark Class Reference
You can get city, country and iso country code using this (Swift 5):
private func getAddress(from coordinates: CLLocation) {
CLGeocoder().reverseGeocodeLocation(coordinates) { placemark, error in
guard error == nil,
let placemark = placemark
else
{
// TODO: Handle error
return
}
if placemark.count > 0 {
let place = placemark[0]
let city = place.locality
let country = place.country
let countryIsoCode = place.isoCountryCode
}
}
}

Error when assigning NSString variable in a block

- (NSString *) geocodeAddressFromCoordinate:(CLLocationCoordinate2D)coordinate
{
CLLocation *location = [[CLLocation alloc]initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
__block NSMutableString * address = [NSMutableString string];
geocoder = [[CLGeocoder alloc]init];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error)
{
if (error) {
NSLog(#"%#", [error localizedDescription]);
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"No results were found" message:#"Try another search" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil, nil];
alert.show;
return;
}
if ([placemarks count]>0)
{
NSLog([placemarks description]);
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(placemark.locality);
//This line makes an error
[address initWithString:placemark.locality];**
}
}];
return address;
}
Got following runtime error:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* initialization method
-initWithCharactersNoCopy:length:freeWhenDone: cannot be sent to an abstract object of class __NSCFString: Create a concrete instance!'
You should never call 'initWithString:' without a matching alloc. Looks more like what you want is [address setString:placemark.locality]
You have already initialized address with this line [NSMutableString string]; so your call to [address initWithString:placemark.locality]; is trying to initialize an already initialized object.
Change this:
[address initWithString:placemark.locality];
To:
[address setString:placemark.locality];
NSString Class Reference
NSMutableString Class Reference
[address initWithString:placemark.locality];
should be something more like:
address = placemark.locality;
or
[address appendString:placemark.locality];
depending on what yu are trying to accomplish.
At this point, your string is already initialized, [NSMutableString string] is a convenience method which essential returns [[[NSMutableString alloc] init] autorelease]. You are trying to re init an already inited object, which is bad.
Change that line to [address appendString:placemark.locality];

Resources