I have an application which creates a class instance that contains (amongst other things) some location data.
In the app delegate I set up location services and start grabbing the location data;
//Delegate method to receive location information from locationManager
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
latestLocation = newLocation;//Make latest location the same as NewLocation
NSLog(#"Location is: %#", latestLocation);
}
I declare latest location as a property so that I can get at the CLLocation instance from another class.
My captures class, when called grabs the CLLocation when its init method is called;
//Designated initialiser
-(id) initWithVideoPath:(NSString *) vPath
userNotes:(NSString *) uNotes
retentionState:(NSString *) rState
{
//Call the super classes designated initializer
[super init];
//Get a pointer to the application delegate so we can access the location props
Rolling_VideoAppDelegate *appDelegate = (Rolling_VideoAppDelegate*)[UIApplication sharedApplication].delegate;
//If superclass failed to init
if (!self)
return nil;
//Give the variables some initial values
[self setVideoPath:vPath];
[self setUserNotes:uNotes];
[self setRetentionState:rState];
dateCreated = [[NSDate alloc] init];
mp = [[MapPoint alloc]initWithCoordinate:[[appDelegate latestLocation]coordinate]];//get the location from the coords from appDelegate
return self;
[dateCreated release];
}
However the app crashes when the mapPoint init is called. The problem is I'm not getting the CLLocation information in properly.
I'm still unsure why the original solution does not work, so if anyone has any insights please do enlighten.
I have however worked out a slightly inelegant work around using NSUserDefaults
latestLocation = newLocation;//Make latest location the same as NewLocation
//Use NSUser Defaults to save the CLLocation instance
NSUserDefaults *location = [NSUserDefaults standardUserDefaults];
[location setDouble:latestLocation.coordinate.latitude forKey:#"lat"];
[location setDouble:latestLocation.coordinate.longitude forKey:#"longd"];
I needed to break out the lat and long as NSUserDefaults will not store CLLocation objects (NSCoding compatability), the reconstruct them in the captures class;
NSUserDefaults *location = [NSUserDefaults standardUserDefaults];//Get a handle to the user defaults
CLLocationDegrees lat = [location doubleForKey:#"lat"];
CLLocationDegrees longd = [location doubleForKey:#"longd"];
CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:lat longitude:longd];
mp = [[MapPoint alloc]initWithCoordinate:[currentLocation coordinate]];//get the location from the coords from appDelegate
Related
I wrote a simple iOS application that retrieves location information and then uses the location to request Yahoo Weather.
The problem is that even when I call the Core Location in the viewDidLoad, it won't give me the result immediately.
So why can't I get the location information?
How can I get the location information in viewDidLoad?
The pseudocode currently is something like:
- (void)viewDidLoad
{
[super viewDidLoad];
self.locManager = [[CLLocationManager alloc] init];
self.locManager.delegate = self;
self.locManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locManager.distanceFilter = 100;
[self.locManager startUpdatingLocation];
//won't get the current location right now, so the output will be null
NSLog(#"Current Location Longitude: %#", self.longitudeString);
NSLog(#"Current Location Latitude: %#", self.latitudeString);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations lastObject];
self.longitudeString = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
self.latitudeString = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
Location updates are not provided as instantly as you are expecting, you need to wait few seconds (2-3 or may be more) to get precise location update. If you want to have location data in viewDidLoad then you should init your location manager (and call startUpdatingLocation) before invoking the ViewController (since then it is not guaranteed that you will have location-data in viewDidLoad).
I want the current latitude and longitude of my device. I can print latitude and longitude when my program locate the device for the first time but I can't refresh it.
-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
int lastindex = [locations count]-1;
CLLocation * currentLocation = [locations objectAtIndex:lastindex];
float latitude =currentLocation.coordinate.latitude;
float longitude =currentLocation.coordinate.longitude;
NSLog(#"LAT:%f LONG:%f",latitude,longitude);
[self latitudeLabel].text = [[NSString alloc]initWithFormat:#"latitude : %#",[[NSNumber numberWithFloat:latitude] stringValue]];
[self longitudeLabel].text = [[NSString alloc]initWithFormat:#"longitude : %#",[[NSNumber numberWithFloat:longitude] stringValue]];
}
This is what I tried but latitude/longitude are never updated. I tried it with the function didUpdateHeading but that didn't work either.
How can i do this. Any one can help me to solve this issue.
Thanks you
This method is triggered by startUpdatingLocation which I assume you're using since it did get called at least once. The method gets called each time the location data changes. Is your location actually changing enough to trigger it? Also, check the distanceFilter property on your CLLocationManager and make sure it is low enough.
Make sure you add the following to your header:
#interface YourLocationObject : SomeObject <CLLocationManagerDelegate>
.. and when you create your CLLocationManager object, you set yourself as the delegate:
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
//... other customization here ...//
[locationManager startUpdatingLocations];
I am working on a simple application that gathers a users current data in a location model. That is working and I can log the locations. However, no viewControllers are seeing the updated variable. I am using KVO in the viewControllers to fire but it seems that CLLocation does not send using 'NSKeyValueObservingOptionNew'. It will fire if I use the 'NSKeyValueObservingOptionInitial' but this fires before the CLLocationManager has had an opportunity to set the instance.
Does anyone know why CLLocation is not sending the "...New" value? Like I said, it is working only when it is set to the "...Initial" state.
Thoughts?
View Controller Code:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqual:#"locationUpdated"]) {
CLLocation *locationVariable = [[CLLocation alloc]init];
locationVariable = self.location.currentLocation;
NSLog(#"the location vaiable: %#", locationVariable);
self.theMap.centerCoordinate = self.location.currentLocation.coordinate;
}
}
Location Model Code:
- (void)startLocationManger {
if ([self locationManager] == nil) self.locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[_locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *locationFix = [locations lastObject];
_currentLocation = locationFix;
NSLog(#"Current Location: %#", _currentLocation);
}
The main reason the KVO notification is not firing from the Location Model code is probably this line in the locationManager:didUpdateLocations delegate method:
_currentLocation = locationFix;
The code is assigning a value directly to the backing variable of the property you want to observe.
Automatic KVO notifications only fire if you use the synthesized property setter:
self.currentLocation = locationFix; // <-- assign using self.xxx
A bit unrelated but in the observeValueForKeyPath method:
I'm not sure why you're checking if ([keyPath isEqual:#"locationUpdated"]). Are you sure that's the keyPath you want to look for?
In this code:
CLLocation *locationVariable = [[CLLocation alloc]init];
locationVariable = self.location.currentLocation;
the alloc+init is unnecessary since the variable is then immediately assigned a new value. Just do:
CLLocation *locationVariable = self.location.currentLocation;
I'm trying to develop an Altimeter on Xcode and Simulator but it always return 0 for the height above the sea.
I don't understand why, I've tried with a lot of places on Simulator.
My code is this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_mapView.delegate = self;
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_locationManager.pausesLocationUpdatesAutomatically = YES;
_locationManager.delegate = self;
firstLocation = YES;
checkUserLocation = NO;
}
- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
CLLocation *location = [locations lastObject];
lastLocation = location.coordinate;
_latitudeLabel.text = [NSString stringWithFormat:#"Current latitude: %f", location.coordinate.latitude];
_longitudeLabel.text = [NSString stringWithFormat:#"Current longitude: %f", location.coordinate.longitude];
_altitudeLabel.text = [NSString stringWithFormat:#"Current altitude: %f m", location.altitude];
}
Where is my error?
There's nothing wrong with your code, its because you are using the simulator.
Determining altitude requires a device with GPS capabilities, and you also need to be using GPS on that device in order to get it (wifi only location would not report altitude correctly even on GPS-enabled devices). The iOS simulator does not have those capabilities so altitude will not be accurate there. You will need to use a real device with GPS to get altitude measurements.
If you want to simulate a CLLocation with altitude you can create your CLLocation object and pass it an altitude yourself:
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate
altitude:(CLLocationDistance)altitude
horizontalAccuracy:(CLLocationAccuracy)hAccuracy
verticalAccuracy:(CLLocationAccuracy)vAccuracy
timestamp:(NSDate *)timestamp
Altitude is a readonly property so you will need to create a new CLLocation object yourself instead of changing it manually when you receive a CLLocation object in your delegate callback.
I have a CoreLocation manager in VC, when user pressed "get direction" button, I initalize location manager, and app opens google map direction with current location and some pre defined destination location.
Here is my problem, if app is not in background state, current location nearly always true, bu if app calling from background in same VC and user pressed again "get direction" button , current location generally shows old locations. In short, I'm troubling with multitasking and timestamp of retrieved locations did not solved my problem.
IBAction:
if ( self.locationManager ) {
[_locationManager release];
self.locationManager = nil;
}
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationTimer = [NSTimer scheduledTimerWithTimeInterval:LOCATION_TIMER target:self selector:#selector(stopUpdatingLocationTimer) userInfo:nil repeats:NO];
HUD = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
[self.locationManager startUpdatingLocation];
Core Location Delegate:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"%f",locationAge);
if (locationAge > 3.0)
return;
if (newLocation.horizontalAccuracy < 0)
return;
if ( self.currentLocation == nil || self.currentLocation.horizontalAccuracy > newLocation.horizontalAccuracy ) {
self.currentLocation = newLocation;
if (self.currentLocation.horizontalAccuracy <= self.locationManager.desiredAccuracy) {
[self stopUpdatingLocations:YES];
}
}
}
In your example locationAge is a negative representation of the number of seconds since the timestamp of newLocation. This means that locationAge will never be greater than 3 and you're effectively letting every update through the sieve.
Set locationAge like this:
NSTimeInterval locationAge = [newLocation.timestamp timeIntervalSinceNow];
For those who encounter same problem,
Also, some tutorials related with core location on web, lead me this problem.
Of course, I keep CLLocation ivar in my VC, whenever CLLocation ivar
sets and google maps called, my app goes to background.
Then, my app calls from background by user, and start updating locations,
and old CLLocation ivar is not nil and probably best horizantal accuracy then
newly comes. Therefore;
if ( self.currentLocation == nil || self.currentLocation.horizontalAccuracy > newLocation.horizontalAccuracy )
this line cause problems, and old location in CLLocation ivar
never replaced.
So I changed viewDidDisappear like this and I assigned nil value to CLLocation variable and works perfectly.
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.locationManager stopUpdatingLocation]; // CLLocationManager
self.locationManager = nil;
[self.locationTimer invalidate]; // NSTimer
self.locationTimer = nil;
self.currentLocation = nil; // CLLocation
}
p.s : thank you Mark Adams