I am trying to write a latitude value and longitude value to a plist inside a LocationManager method.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSString *latitude = [[NSString alloc] initWithFormat:#"%g", newLocation.coordinate.latitude];
NSString *longitude = [[NSString alloc] initWithFormat:#"%g", newLocation.coordinate.longitude];
NSString *filePath = [[NSBundle mainBundle] pathForResource:
#"PlayerData" ofType:#"plist"];
NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
[plistDict setValue:latitude forKey:#"MyLatitude"];
[plistDict setValue:longitude forKey:#"MyLongitude"];
[plistDict writeToFile:filePath atomically: YES];
myLatitude.text = latitude;
myLongitude.text = longitude;
NSLog(#"Location: %#", [newLocation description]);
}
For some reason it never writes the value to the plist, but prints out the values correctly.
NSLog(#"Lat i s:%# Lon is :%#", latitude, longitude);
What would cause this not to update/write to the plist?
Thanks
iOS applications are sandboxed, so you can't write to the application bundle. You need to write to one of these directories. Which one you need to write to depends on what kind of data it is.
You can't write to the main bundle (may work in simulator but not device).
Try saving the file to the Documents folder instead.
Related
I am using this code in which I am getting Placemark but it not giving the city name.
Earlier I am using MKReverse Geocoder to get the placemark in which I am getting the city name but as in iOS 6 it showing deprecated because the Apple developer added everything in CLLocation.
So I used this code:
-(void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocation *location = [locationManager location];
NSLog(#"location is %#",location);
CLGeocoder *fgeo = [[[CLGeocoder alloc] init] autorelease];
// Reverse Geocode a CLLocation to a CLPlacemark
[fgeo reverseGeocodeLocation:location
completionHandler:^(NSArray *placemarks, NSError *error){
// Make sure the geocoder did not produce an error
// before continuing
if(!error){
// Iterate through all of the placemarks returned
// and output them to the console
for(CLPlacemark *placemark in placemarks){
NSLog(#"%#",[placemark description]);
city1= [placemark.addressDictionary objectForKey:(NSString*) kABPersonAddressCityKey];
NSLog(#"city is %#",city1);
}
}
else{
// Our geocoder had an error, output a message
// to the console
NSLog(#"There was a reverse geocoding error\n%#",
[error localizedDescription]);
}
}
];
}
Here as I am seeing in console in NSLog(#"%#",[placemark description]);
it's giving output like :- abc road name,abc road name, state name,country name.
If you want to NSLog the address you have to compose it doing something like this:
NSString *street = [[placemark addressDictionary] objectForKey:(NSString *)kABPersonAddressStreetKey];
NSString *city = [[placemark addressDictionary] objectForKey:(NSString *)kABPersonAddressCityKey];
NSString *state = [[placemark addressDictionary] objectForKey:(NSString *)kABPersonAddressStateKey];
NSString *country = [[placemark addressDictionary] objectForKey:(NSString *)kABPersonAddressCountryKey];
NSString *zip = [[placemark addressDictionary] objectForKey:(NSString *)kABPersonAddressZIPKey];
NSString *message = [NSString stringWithFormat:#"Address Is: %#, %# %#, %#, %#", street, zip, city, state, country];
NSLog(#"%#", message);
Or you can iterate through the array returned by:
NSArray *array = [[placemark addressDictionary] objectForKey:#"FormattedAddressLines"];
If you want to simply print the dictionary content, do:
NSLog(#"%#", [[placemark addressDictionary] description]);
Three things that I can see could use some attention...
First, this method is deprecated (see documentation here):
(void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
Try using this instead:
(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
Your most current location is the last item in the array locations so:
/*
According to the Apple docs, the array of locations keeps the most recent location as the
last object in the array
*/
CLLocation *location = [locations lastObject];
NSLog(#"%#", location);
Second, if you're using ARC, the autorelease message is unnecessary: CLGeocoder *fgeo = [[CLGeocoder alloc] init]; works fine.
Lastly, according to the Apple documentation for CLPlacemark has a property locality which should return the city for the placemark. So
for(CLPlacemark *placemark in placemarks){
NSLog(#"%#",[placemark description]);
NSString *city1 = [placemark locality];
NSLog(#"city is %#",city1); }
If you just want the city, the addressDictionary property seems to be overkill. According to the documentation here addressDictionary is formatted to return stuff in an ABPerson object, which I'd assume you'd have to parse to get the city. Placemark locality seems much simpler...
I tested my suggestions in a Geocoding app that I'm building and I got the result you're looking for via [placemark locality]
Currently i am working in iPhone application, Using CLLocationManager to get Latitude and Longitude values fine.
I didn't know this? How to get the device location (Address) name from this latitude and longitude value? please help me
Thanks in Advance
I tried this:
- (void)viewDidLoad
{
[super viewDidLoad];
LocationManager = [[CLLocationManager alloc]init];
LocationManager.delegate=self;
LocationManager.desiredAccuracy = kCLLocationAccuracyBest;
[LocationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSString * latitude = [[[NSString alloc] initWithFormat:#"%f", newLocation.coordinate.latitude]autorelease];
NSString * longitude = [[[NSString alloc] initWithFormat:#"%f", newLocation.coordinate.longitude]autorelease];
[LocationManager stopUpdatingLocation];
NSLog(#"latitude:%#",latitude);
NSLog(#"longitude:%#",longitude);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[manager stopUpdatingLocation];
lati = [[NSString alloc] initWithFormat:#"%+.6f", newLocation.coordinate.latitude];
NSLog(#"address:%#",lati);
longi = [[NSString alloc] initWithFormat:#"%+.6f", newLocation.coordinate.longitude];
NSLog(#"address:%#",longi);
[geoCoder reverseGeocodeLocation: newLocation 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);
address = [[NSString alloc]initWithString:locatedAt];
NSLog(#"address:%#",address);
}];
}
CLGeocoder *ceo = [[CLGeocoder alloc]init];
CLLocation *loc = [[CLLocation alloc]initWithLatitude:32.00 longitude:21.322];
[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(#"placemark %#",placemark.country); // Give Country Name
NSLog(#"placemark %#",placemark.locality); // Extract the city name
NSLog(#"location %#",placemark.name);
NSLog(#"location %#",placemark.ocean);
NSLog(#"location %#",placemark.postalCode);
NSLog(#"location %#",placemark.subLocality);
NSLog(#"location %#",placemark.location);
//Print the location to console
NSLog(#"I am currently at %#",locatedAt);
}];
You have ta make some reverse location. You're lucky : Apple provides a class to do that.
See CLGeocoder (for iOS >= 5.0) or MKReverseGeocoder (for iOS < 5.0)
You can use Google Maps API for this (works on any iOS):
NSString *req = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?latlng=%.5f,%.5f&sensor=false&language=da", location.latitude, location.longitude];
NSString *resultString = [NSString stringWithContentsOfURL:[NSURL URLWithString:req] encoding:NSUTF8StringEncoding error:NULL];
Then you can parse this response to NSDictionary using Any JSON library (SBJSON in this case):
SBJSON *jsonObject = [[SBJSON alloc] init];
NSError *error = nil;
NSDictionary *response = [jsonObject objectWithString:resultString error:&error];
[jsonObject release];
Extracting address:
if (error) {
NSLog(#"Error parsing response string to NSObject: %#",[error localizedDescription]);
}else{
NSString *status = [response valueForKey:#"status"];
if ([status isEqualToString:#"OK"]) {
NSArray *results = [response objectForKey:#"results"];
int count = [results count];
//NSSLog(#"Matches: %i", count);
if (count > 0) {
NSDictionary *result = [results objectAtIndex:0];
NSString *address = [result valueForKey:#"formatted_address"];
}
}
}
You have to create a CLLocation object and pass that on to reverseGeoCoder.
Before iOS 5.0 we have MKReverse Geo-coder class to find this..Now it is deprecated..
We have to use CLGeocoder class in Core Location Framework
I use the location manager with "didUpdateToLocation". I have a memory leak that I cannot explain:
- (void) locationManager:(CLLocationManager *) manager didUpdateToLocation:(CLLocation *) newLocation
fromLocation:(CLLocation *) oldLocation {
[newLocation retain];
NSString *lCoordinates = [[NSString alloc] initWithFormat:#"%f,%f",newLocation.coordinate.latitude,newLocation.coordinate.longitude];//Memory leak here!!!
[self setLocationCoordinates:lCoordinates];
[lCoordinates release];
NSString *lat = [[NSString alloc] initWithFormat:#"%f,%f", newLocation.coordinate.latitude,newLocation.coordinate.longitude];
[lm stopUpdatingLocation];
NSMutableString *s = [[NSMutableString alloc]initWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?location=%#&radius=10&sensor=true&key=---MyKey---", lat];
NSLog(s);
id delegate = self;
AsyncConnectionController * connectionController = [[[AsyncConnectionController alloc] initWithDelegate:delegate
selSucceeded:#selector(currentLocationConnectionSucceeded:)
selFailed:#selector(currentLocationconnectionFailed:)] autorelease];
NSURL *url = [[NSURL alloc] initWithString:s];
[connectionController startRequestForURL:url];
[lat release];
[s release];
[url release];
[newLocation release];
}
Thanks all for your help!!!
You should be able to reduce your code substantially just by using convenience methods (makes it more readable as well):
- (void) locationManager:(CLLocationManager *) manager didUpdateToLocation:(CLLocation *) newLocation fromLocation:(CLLocation *) oldLocation {
NSString *lCoordinates = [NSString stringWithFormat:#"%f,%f",newLocation.coordinate.latitude,newLocation.coordinate.longitude];
[self setLocationCoordinates:lCoordinates];
NSString *lat = [NSString stringWithFormat:#"%f,%f", newLocation.coordinate.latitude,newLocation.coordinate.longitude];
[lm stopUpdatingLocation];
NSString *s = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?location=%#&radius=10&sensor=true&key=---MyKey---", lat];
NSLog(s);
AsyncConnectionController * connectionController = [[[AsyncConnectionController alloc] initWithDelegate:self
selSucceeded:#selector(currentLocationConnectionSucceeded:)
selFailed:#selector(currentLocationconnectionFailed:)] autorelease];
NSURL *url = [NSURL urlWithString:s];
[connectionController startRequestForURL:url];
}
OP specifies that connectionController is autorelease.
Here's the full method, I didn't put the second half originally because I know it works:
-(void)showDirections
{
locationManager = [[CLLocationManager alloc] init];
[locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
[locationManager setDelegate:self];
CLLocation *location = [locationManager location];
CLLocationCoordinate2D coordinate = [location coordinate];
NSNumber *myLatitude = [NSNumber numberWithDouble:coordinate.latitude];
NSNumber *myLongitude = [NSNumber numberWithDouble:coordinate.longitude];
double myLatitude2 = [myLatitude doubleValue];
double myLongitude2 = [myLongitude doubleValue];
NSArray *array = [dataHold objectForKey:#"Subtree"];
NSString *latitude = [NSString stringWithFormat:#"%#",[array objectAtIndex:4]];
NSString *longitude = [NSString stringWithFormat:#"%#",[array objectAtIndex:5]];
double clubLatitude = [latitude doubleValue];
double clubLongitude = [longitude doubleValue];
CLLocationCoordinate2D start = { myLatitude2, myLongitude2};
CLLocationCoordinate2D destination = { clubLatitude, clubLongitude};
NSString *googleMapsURLString = [NSString stringWithFormat:#"http://maps.google.com/?saddr=%1.6f,%1.6f&daddr=%1.6f,%1.6f",start.latitude, start.longitude, destination.latitude, destination.longitude];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:googleMapsURLString]];
}
Two issues:
1) You are doing a NSNumber box/unbox cycle that has no use whatsoever
2) Core Location is asynchronous, therefore you cannot return the user's location straight away, you must use the delegate method(s) to retrieve the location if/when it is available.
Here's an example of how it should work:
-(void)showDirections
{
locationManager = [[CLLocationManager alloc] init];
[locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
[locationManager setDelegate:self];
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocationCoordinate2D coord = [newLocation coordinate];
NSArray *array = [dataHold objectForKey:#"Subtree"];
NSString *latitude = [NSString stringWithFormat:#"%#",[array objectAtIndex:4]];
NSString *longitude = [NSString stringWithFormat:#"%#",[array objectAtIndex:5]];
double clubLatitude = [latitude doubleValue];
double clubLongitude = [longitude doubleValue];
NSString *googleMapsURLString = [NSString stringWithFormat:#"http://maps.google.com/?saddr=%1.6f,%1.6f&daddr=%1.6f,%1.6f", coord.latitude, coord.longitude, clubLatitude, clubLongitude];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:googleMapsURLString]];
}
The fourth line of your code is where the problem begins. You cannot get the location instantly, you will need to wait until the location services notify the delegate that a location is available. I will add some comments to your code to explain:
-(void)showDirections
{
locationManager = [[CLLocationManager alloc] init];
[locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
[locationManager setDelegate:self];
// this is not where you should be looking
CLLocation *location = [locationManager location];
// the rest of this function is not included in this example ...
}
Since you set the delegate as "self", the current class but implement the "CLLocationManagerDelegate" protocol, which defines the following two functions:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { /* */ }
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { /* */ }
That is where you will get a location provided to you.
Dont forget to update your class definition like so:
#interface MyClass : NSObject <CLLocationManagerDelegate> {
And as a side note, it seems like you do not fully understand delegates and the purpose that they serve, which is fine if you are new to Objective-C, but getting more familiar with them will certainly make your life a bit easier.
Some other helpful stuff:
A CoreLocation Tutorial (covers what you are trying to do)
I am getting an EXC_BAD_ACCESS out side of my own code. Currently my code gets a URL through a shareURLCache object and then starts url connection. Once I leave the method that starts the url connection I hit the EXC_BAD_ACCESS. I have tried using instruments to find any zombies and I have analysed for memory leaks and not turned up either. At this point I am completely stuck.
Here is the code that loads the url and starts the url connection
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSLog(#"At new location: %#",newLocation);
MKCoordinateRegion region =
MKCoordinateRegionMakeWithDistance([newLocation coordinate], 750, 750);
[mapView setRegion:region animated:YES];
[location stopUpdatingLocation];
CLLocationCoordinate2D coord = [newLocation coordinate];
NSURL *url = [urlCache getReccomendationForUID:#"12345" atLat:coord.latitude
atLon:coord.longitude forCategories:nil];
// Create the request.
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
if (connection) {
// Create the NSMutableData to hold the received data.
// xmlData is an instance variable declared elsewhere.
xmlData = [[NSMutableData alloc]init];
} else {
NSLog(#"Could not create connection");
}
}
Method from the sharedURLCache that returns the url
-(NSURL *)getReccomendationForUID:(NSString *)u atLat:(double)lat atLon:(double)lon forCategories:(NSArray *)cat
{
if(remote) {
NSMutableString *categories = [[NSMutableString alloc]init];
for(NSString *s in cat) {
[categories appendString:#"&cat="];
[categories appendString:s];
}
NSString *s = [NSString stringWithFormat:#"%#/recommendation?uid=%#&psw=null&lat=%f&lon=%f?%#",
apiRoot,u,lat,lon,categories];
[categories release];
return [NSURL URLWithString:s];
} else {
return [[NSBundle mainBundle] URLForResource:#"XMLTest" withExtension:#"xml"];;
}
}
Just start by commenting out code and running to see if you can get the mem error to disappear then start adding code again until it appears, then you have a better idea where the issue is. it could be anywhere in your code since you seem to have a number of objects in there that are not passed in e.g. 'location'.
[location stopUpdatingLocation];
I had same memory issue with
[mapView setRegion:region animated:YES];
This method doesn't like fast updates...