This is one awful bug. When using CLLocationManger, either with startUpdatingLocation or with ALAsset methods to access metadata for a photo, the system is prompting for location access as expected...but the prompt disappears as soon as it's shown. I cannot find the reason for this and am hoping someone else has had this problem. This does not occur with other alerts (such as showing a UIAlertView).
I can even set the purpose property, and it displays, but again, only for a moment then it just closes itself.
This is a big issue for me as I require permission in order to use photo metadata.
Are you creating the CLLocationManager instance in a method like so:
-(void) viewDidAppear:(BOOL)animated {
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
}
If so, then as soon as the function exits, the local locationManager variable is being cleaned up. You should save a reference to the locationManager either on an instance or in a static variable:
static CLLocationManager *locationManager;
-(void) viewDidAppear:(BOOL)animated {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
}
Ugh, now the issue appears to be resolved. And I don't know why or how.
Related
I have mkmapview delegate to handle authorization events, etc., however, my userLocation is real, but my userLocation.location always returns nil in simulator or on device.
Any pointers on why?
Be sure you have added :
NSLocationWhenInUseUsageDescription in your info.plist project file
Register for CLLocationManagerDelegate
mapView.showsUserLocation=YES;
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
[locationManager requestWhenInUseAuthorization];
[locationManager startUpdatingLocation];
}
Hope it will help
Test this behavior on your device is Simpler ( or don't forget to set a location in your simulator configuration )
In the view didload method
I'm calling
/**initialize location manager**/
if (nil == locationManager)
locationManager = [[CLLocationManager alloc] init];
//set the delegate for the location manager
//locationManager.delegate = self;
// set your desired accuracy
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
[locationManager startUpdatingLocation];
To get permission from user while the Tableview is loading.
How can I catch the event that user authorized the app to get permission at anytime
status == kCLAuthorizationStatusAuthorized
then reload table?
Register a CLLocationManagerDelegate on your location manager instance with -[CLLocationManager setDelegate:]. Your delegate should implement -[CLLocationManagerDelegate locationManager:didChangeAuthorizationStatus:].
Currently, developing an app that needs to get last location from CLLocationManager (without any regular tracking). It doesn't matter how old, accurate it is. I don't need and want to start tracking - I just need to just grab some last location from a cache and that's it. IMHO, CLLocationManager is a shared component in iOS and if some app uses location tracking then another app should be able to use the most recent location from CLLocationManager.location. It should be sufficient just to alloc/init CLLocationManager and grab its location. However it's not. I have tested on iPhone4 - started google maps, saw my current location, then went to my app, but after [[CLLocationManager alloc] init] location property is nil.
UPDATE: tried [locationManager startUpdatingLocation]; and [locationManager stopUpdatingLocation]; but the result is the same. I guess, the only solution is to start regular tracking?
UPDATE2: Strange but there's no alert with "The app wants to use location services" after alloc/init of CLLocationManager. Here's my code fragment:
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
[locationManager startUpdatingLocation];
[locationManager stopUpdatingLocation];
NSLog(#"%#", locationManager.location); //prints nil
First you should check if your locationManager has a, let's say, 'static' location pre-saved.
If it does, you're done.
If not, you should startUpdatingLocation and then, in the didUpdateToLocation:fromLocation: callback, stopUpdatingLocation once you get the location.
My experience says that's the best way to get only one location.
UPDATE TO MATCH AUTHOR UPDATES:
You should not stopUpdatingLocation just after startUpdatingLocation. startUpdatingLocation starts a service in background, so you should wait until you get a location, so invoque it in the callback methods.
To make any use of CLLocationManager you need to implement CLLocationManagerDelegate somewhere.
-[CLLocationManager startUpdatingLocation] starts an async process. If you stop it in the same runloop cycle the process never gets started and that is the reason you never see the permission dialog.
It goes something like this:
#interface MyClass : NSObject <CLLocationManagerDelegate> {
CLLocationManager *manager;
CLLocation *lastLocation;
}
#end
#implementation
- (id)init {
self = [super init];
if (self) {
manager = [[CLLocationManager alloc] init];
manager.delegate = self;
[manager startUpdatingLocation];
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation;
{
lastLocation = newLocation;
[manager stopUpdatingLocation];
}
// in your real implementation be sure to handle the error cases as well.
#end
Is it possible to start / stop location updates from the UI of the iphone? All I need from the app is to show me my location unless I click "stop" and then "start" again.
I can't seem to be able to do that...I have my location displayed properly, and I also created two IBButtons and created a function for each of them, however, my app crashes when I click on each one of those buttons. I placed those functions under the viewcontroller.m.
I am kind of new to this, so any help would be appreciated. Thanks!
(IBAction)startUpdating: (CLLocation *)location
{
[location startUpdatingLocation];
}
(IBAction)stopUpdating: (CLLocation *)location
{
[location stopUpdatingLocation];
}
start/stopUpdatingLocation are CLLocationManager instance methods, rather than CLLocation instance methods... so create a CLLocationManager instance.
.h
#interface someClass:somesuperclass{
CLLocationManager * locationManager;
BOOL updating;
}
-(IBAction)toggleUpdating:(id)sender;
#end
.m somewhere in the view load/ or init cycle:
-(void)viewDidLoad{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
}
-(void)viewDidUnload{
[locationManager stopUpdatingLocation];
[locationManager release];
[super viewDidUnload];
}
-(IBAction)toggleUpdating:(id)sender
{
if(!updating)
{
[locationManager startUpdatingLocation];
}else{
[locationManager stopUpdatingLocation];
}
updating = !updating;
}
also your action above will never work, because the thing after a colon in an action will be the object that sent the action, a UIButton in your case.
I have noticed in a few books that quite often two instances of CLLocationManager are created, one for location and a separate one for heading. If you wanted a separate delegate for each I could see the point, but all the methods are unique so I can't really think of a reason for doing this. Is there something I am missing, or is it possible to simplify this and use one CCLocationManager for both location and heading?
// LOCATION
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[customMapView setShowsUserLocation:YES];
// HEADING:
headingManager = [[CLLocationManager alloc] init];
[headingManager setDelegate: self];
[headingManager setHeadingFilter:kCLHeadingFilterNone];
[headingManager startUpdatingHeading];
I've never done this and all my apps have worked absolutely fine - I'd just use the same one for both :)
I can't even begin to think of a reason why you would do this if the delegates were the same!