I want to get current location of device. Code works fine normally. It gives location if user has not changed app authorization status for location service. I am also able to check if user has denied permission for location service.
Issue is when user deauthorizes the app to use location service and then authorizes again. In this case, after this if I try to get location it gives nil though it called
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
delegate method with status 3 i.e. kCLAuthorizationStatusAuthorized.
Code to get current location :
CLLocation * location = self.locationManager.location;
Getter method :
- (CLLocationManager *)locationManager
{
if (!locationManager)
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
}
return locationManager;
}
CLLocationManager delegate method :
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
DLog(#"Location authorization changed : %d", status);
// If user has denied permission for location service
if (status == kCLAuthorizationStatusDenied)
{
DLog(#"Location service denied.");
// If authorization status changed method is already called, then SDK will not call again on same object.
// Thus, set CLLocationManager object to nil so that next time we try to get location, it will create a new object,
// and that will send message about authorization status changed.
self.locationManager.delegate = nil;
self.locationManager = nil;
}
else if (status == kCLAuthorizationStatusNotDetermined)
{
// If authorization status changed method is already called, then SDK will not call again on same object.
// Thus, set CLLocationManager object to nil so that next time we try to get location, it will create a new object,
// and that will send message about authorization status changed.
self.locationManager.delegate = nil;
self.locationManager = nil;
}
else if (status == kCLAuthorizationStatusAuthorized)
{
}
}
Any idea about this?
self.locationManager.location is nil since you never started updating the location.
In the apple docs it is stated about the location property of the locationManager:
The value of this property is nil if no location data has ever been
retrieved.
For this reason you need to somehow update your iPhones location!
Apple Docs CLLocationManager
Usually this means you want to call
[self.locationManager startUpdatingLocation]
but you can also use
[self.locationManager startMonitoringSignificantLocationChanges]
If you set the delegate to nil you will get no updates about authorization status changes, isn't it?
self.locationManager.delegate = nil;
I think you should keep the delegate in order to receive authorization status updates and then call the startUpdatingLocation method in order to get the current location.
- (void)startUpdatingLocation
Related
I have an app that is tracking a User's location. I have much experience with this and have requested when in use Authorization and have added the key to my P-List, however I still receive this error:
"Trying to start MapKit location updates without prompting for
location authorization. Must call -[CLLocationManager
requestWhenInUseAuthorization] or -[CLLocationManager
requestAlwaysAuthorization] first."
The location Manager that I am using is not in the ViewController but in another class.
It doesn't matter where those methods are called from, so you could call either of those methods either from your app delegate's applicationDidFinishLaunching method (these authorization methods run asynchronously) or in the viewDidAppear method of your very first view controller.
check the [CLLocationManager authorizationStatus] before setting mapView.showsUserLocation = YES or startUpdatingLocation
Make sure that your CLLocation variable is strong.
(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedWhenInUse) //or kCLAuthorizationStatusAuthorizedAlways
{
self.mapView.showsUserLocation = YES;
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
You must use anyone of the authorization
self.locationManager.requestWhenInUseAuthorization(); or self.locationManager.requestAlwaysAuthorization();
Anyhow the warning will not come for the second time after the user accept the permission
I'm able to get my Current Location using CoreLocation framework. I want to register my current location so that i want to know who has entered and exited the region. For that i have used apple documented method to register a region which is - (void)registerRegionWithCircularOverlay:(MKCircle*)overlay andIdentifier:(NSString*)identifier { } . My question is when does this method gets called?
document link : https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/RegionMonitoring/RegionMonitoring.html
Any help?
You must have to take care of permission to access location of user device. So that application is able to track user location.
You can do this by following:
Add a key NSLocationWhenInUseUsageDescription in a .plist file. This is key has a value of type String. You must take care don't use other than String type here.
Ask user to before access to user location, add below line.
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager requestWhenInUseAuthorization];
Below code will start monitoring region:
// Tell location manager to start monitoring for the region
[self.locationManager startMonitoringForRegion:self.myBeaconRegion];
Also override below methods to make sure that region is discovered:
- (void)locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion *)region
{
// We entered a region!
NSLog(#"Entered in region");
}
-(void)locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion *)region
{
// Exited the region
NSLog(#"Exited from region");
}
I am using iBeacons, but am running into a small problem.
On first use the user needs to give permission, we then following is called:
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
[_locationManager requestAlwaysAuthorization];
However, I expected the following delegate method to be called:
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
NSLog(#"Auth status changed: %i", status);
if(status > 3){
// Check if we have to start monitoring beacons
NSLog(#"Do we need to initialise after auth given?");
//[self initialiseLocations];
}
}
I am running iOS 8.0.2, so not sure if this is a bug
This answer might help... it solved it for me at least. Also this website was a good walkthrough for this issue as well.
It looks like you are calling the requestAlwaysAuthorization correctly, but do you call startUpdatingLocation anywhere? Also, double check that in your Info.plist you have the appropriate key and string value added (NSLocationAlwaysUsageDescription since you're using requestAlwaysAuthorization).
Hi I am implementing Location services in my app. First I have to know my Coordinates to get the distance between some places that I have in a list and the device. Then if I go into a place I can make a check in, so, I need to get coordinates again, and the problem is here. Second time I try to get coordinates, the method -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations is not called.. and I can not get new Coordinates.
My manager is located in a NSObject sublcass with this code:
(id)init {
if ( self = [super init] ) {
if ([CLLocationManager locationServicesEnabled])
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
}
}
return self;
}
-(void) checkLongLatitudeAgain {
[locationManager startUpdatingLocation];
}
#pragma mark Delegates de CLLocationManager
//
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
NSLog(#"LON%f", manager.location.coordinate.longitude);
NSLog(#"LAT:%f", manager.location.coordinate.latitude);
NSTimeInterval howRecentNewLocation = [newLocationeventDate timeIntervalSinceNow];
if (manager.location.horizontalAccuracy <= 100.0 && howRecentNewLocation < -0.0 && howRecentNewLocation > -20.0){
//Usar coordenada
[self.delegate getLocationForCheckIn:manager.location];
[self stopUpdatingLocation:#"Fins"];
}
}
// ---------------------------------------------------------------------------------------------------------------------
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
//
if ([error code] != kCLErrorLocationUnknown) {
[self stopUpdatingLocation:NSLocalizedString(#"Error", #"Error")];
}
//
}
// ---------------------------------------------------------------------------------------------------------------------
- (void)stopUpdatingLocation:(NSString *)state {
//Detenemos la lectura del GPS
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
NSLog(#"Stop gps");
//
}
I call the class when the list of places is open, and also when inside a place the user press checkIn button. Both times I do it with this code:
WPLocationManager *location = [[WPLocationManager alloc]init];
[location checkLongLatitudeAgain];
You are creating a new manager every time:
WPLocationManager *location = [[WPLocationManager alloc]init];
[location checkLongLatitudeAgain];
That new manager is not assigned to any delegate.
You need to use the previous manager you have created and assigned to your delegate, something like:
[locationManager checkLongLatitudeAgain];
You can check the documentation at http://developer.apple.com - https://developer.apple.com/library/ios/documentation/userexperience/conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html
In particular you can check the Starting the Standard Location Service and Starting the Significant-Change Location Service sections. You have to use the startMonitoringSignificantLocationChanges or startUpdatingLocation method of CLLocationManager, cache your location somewhere and update it only when a new location is received, otherwise like it is stated in the documentation: "If a location update has already been delivered, you can also get the most recent location data directly from the CLLocationManager object without waiting for a new event to be delivered".
i dont know why you are initiating your location manager again again, also even if you some how manage to solve current problem but it's not proper way of dealing with location manage based applications.I had been in trouble previously when i was working on location based app. the best approach for location based app is singleton.
apple forum discussion
you can find
this
and this very helpful.
just an advice, :)
Thanks.
In iOS8 for me I had to call [locationManager stopUpdatingLocation]; before calling [locationManager startUpdatingLocation] to start getting updates second time and it works for me.
I am using the Core Location framework to locate the device and once locationManager:didUpdateToLocation:fromLocation: method is called with a location, I stop tracking the user.
However the first time I launch the app (from a fresh install). When I message startUpdatingLocation of my Location Manager, the user gets the alert to accept or refuse location service.
When I accept the tracking doesn't begin, it's only when I go away and come back to this view controller when startUpdatingLocation is again called that notifications start coming in.
I am implementing locationManager:didChangeAuthorizationStatus: thinking that this would get messaged when the user accepts (or refuses) location services, but it doesn't.
Can anyone point me in the right direction for updating location as soon as the location services message has been dismissed ?
Thanks.
UPDATE WITH CODE SAMPLE
I've got a singleton class which encapsulates my logic, the idea is when the user location is requested, a check on the CLLocation's timestamp is performed and if it's too old, start tracking is messaged, which lazy loads my CLLocationManager iVar,
-(void)startTracking{
if(!self.locationManager)
_locationManager = [[CLLocationManager alloc] init];
if([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied){
[self invalidateUserLocation];
}else{
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
}
}
New location received:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
_userLocation = [newLocation retain];
NSDictionary * info = [NSDictionary dictionaryWithObject:self.userLocation
forKey:#"userLocation"];
[[NSNotificationCenter defaultCenter] postNotificationName:kUserLocationFound
object:self
userInfo:info];
[self stopTracking];
}
Stop tracking:
-(void)stopTracking{
if(!self.locationManager)
return;
[self.locationManager stopUpdatingLocation];
self.locationManager.delegate = nil;
}
When I have a view controller which needs the users location I call userLocation on my singleton object like so. If it's recent, I return the CLLocation, otherwise I return nil and start again. Notice I stop tracking when I receive the first update. But the first time this runs and I get the alert view, nothing is tracked at all.
- (CLLocation*)userLocation
{
if(_userLocation.coordinate.latitude == 0 && _userLocation.coordinate.longitude == 0){
[self startTracking];
return nil;
}else{
NSDate* timeNow = [NSDate date];
NSTimeInterval interval = [timeNow timeIntervalSinceDate:_userLocation.timestamp];
if(interval >10)
[self startTracking];
return _userLocation;
}
}
Did you try calling – locationManager:didChangeAuthorizationStatus: from CLLocationManagerDelegate?
I'm going to guess that you call startTracking when the view controller loads. This is circumvented by the alert which ask for if it's okay. At that point, the start locating message won't be called again so by calling didChangeAuthorizationStatus, you can call your startTracking method.
Something like:
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusDenied) {
//location denied, handle accordingly
}
else if (status == kCLAuthorizationStatusAuthorized) {
//hooray! begin startTracking
}
}
If that's not the case, let me know.