CLLocationManager never calls delegate methods

12,146

Solution 1

So I managed to find a bug. It was in memory management. In my app delegate file I initialized a CoreLocationViewController and added it as a subview to my window, after that I released it and all is well. But, the releasing part was not a good way to go. After I released my ViewController, dealloc method gets called and it releases locationManager.

So the proper thing to do is not to release a ViewController that holds locationManager, or find another way of dealing with it. I'm not quite sure why that was a problem because I thought that after adding a ViewController to a window it gets retained, therefore its localtionManager gets retained as well. If anybody can clear it up for me it would be much appreciated.

Solution 2

In my case, the delegate never gets called because of threading problem

  • the thread that operates LocationManager must have an NSRunLoop set up
  • if you use main thread, you already have a runloop, now you just need to instantiate the manager and use it on main thread

Read this to know more about CLLocationManagerDelegate

Solution 3

Furthermore in iOS8 you must have two extra things:

  • Add a key to your Info.plist and request authorization from the location manager asking it to start.

    • NSLocationWhenInUseUsageDescription

    • NSLocationAlwaysUsageDescription

  • You need to request authorization for the corresponding location method.

    • [self.locationManager requestWhenInUseAuthorization]

    • [self.locationManager requestAlwaysAuthorization]

Code example:

self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
    [self.locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];

Source: http://nevan.net/2014/09/core-location-manager-changes-in-ios-8/

Solution 4

Other posters have mentioned checking for authorization, and you should definitely add that, but I do not think that is your problem. If you were not authorized your didFailWithError: method would be called. This leads to believe something else is going on here.

It may be a good idea to make sure that your location manager is indeed being allocated and while your at it you can fix your memory leak.

Try this:

CLLocationManager* lm = [[CLLocationManager alloc] init];
NSAssert(lm != nil, @"Failed to allocate CLLocation manage");
self.locManager = lm;
[lm release];
self.locManager.delegate = self;
[self.locManager startUpdatingLocation];
// Let's just print what we got
NSLog(@"CLLocationManager is %@", lm);

If your run this your will get one of the following results:

1) if the location manager is returning nil, your program will crash into the debugger (because of NSAssert)

2) if "CLLocationManager is ...." prints and still you see no updates then you have a real mystery on your hands.

3) Nothing prints. That would mean, perhaps due to something incorrectly linked up in Interface Builder, that viewDidLoad is not being called at all.

4) You will get a didFailWithError: call because you are not authorized. Which means that at least everything is working as expected.

As an aside you had a memory leak because you were assigning the result of an alloc directly to a property with the retain attribute. After alloc your count would be +1 after assignment it would +2, so if the view was unloaded and reloaded you would leak.

Hope some of this helps.

Solution 5

This may be nit picky but in viewDidLoad change:

locManager.delegate = self;

to:

self.locManager.delegate = self;

I don't know if it will fix it, but is best to be consistent.

Share:
12,146
paxx
Author by

paxx

After graduating from University, I've spent my summer working and traveling the US. Upon returning to Croatia, I've decided to get a job. After a short hunt, I've ended at Trikoder where I've moved from iOS developer to team lead and finally to the head of mobile development department. Next stop was Undabot, which I co-founded together with guys from Trikoder. As Undabot was a small company I basically ran it as a CTO and shared CEO responsibilities with my co-founder. I was at Undabot for 2,5 years and grow our company from 3 to 12 people (two development teams - iOS/Android). I enjoy side project and currently I'm working on Towny and Thinkless.

Updated on June 09, 2022

Comments

  • paxx
    paxx almost 2 years

    Hi I'm playing around with locations on iPhone and right from the start I ran into problems. I've localized my problem and determined it's CLLocationManager that's bugging me.

    So I developed very simple application. I just have a view controller with a CLLocationManager in it. On view did load I initialize CLLocationManager and start updating. I've also implemented two methods didFailWithError and didUpdateToLocation.

    I've read a lot of questions and what i have learned so fare is this. You have to retain CLLocationManager during initialization. Also it's wise to set CLLocationManagers delegate to nil during unloading of a view (something to do with messages passing to CLLocationManager because framework retains it and it's never properly release)

    All in all I just cant find a decent explanation on what to do and how to make it work.

    Here's my code so if anybody could figure it out I would appreciate it. viewControllers header file

    #import <UIKit/UIKit.h>
    #import <CoreLocation/CoreLocation.h>
    
    @interface CoreLocationViewController : UIViewController <CLLocationManagerDelegate>
    {
        CLLocationManager *locManager;
    }
    
    @property (nonatomic, retain) CLLocationManager *locManager;
    
    @end
    

    viewController .m file

    #import "CoreLocationViewController.h"
    
    
    @implementation CoreLocationViewController
    @synthesize locManager;
    
    - (void)viewDidLoad 
    {
        [super viewDidLoad];
    
        self.locManager = [[CLLocationManager alloc] init];
        locManager.delegate = self;
        [self.locManager startUpdatingLocation];
    
        self.view.backgroundColor = [UIColor grayColor];
    }
    
    #pragma mark -
    #pragma mark Location Delegate
    
    - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
    {
            NSLog(@"in fail with error");
    }
    
    - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
    {
        NSLog(@"in update to location");
    }
    
    
    #pragma mark -
    #pragma mark Memory Management
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
    }
    
    - (void)viewDidUnload 
    {
    self.locManager.delegate = nil;
        [super viewDidUnload];
    }
    
    
    - (void)dealloc 
    {
        [locManager release];
            [super dealloc];
    }
    
    
    @end
    

    BTW: I'm using iOS 4.2. I'm pointing this out because I read that Apple has changed location delegates in iOS 4

  • paxx
    paxx almost 13 years
    tried it.. i used if ([CLLocationManager locationServicesEnabled]) { [self.locManager startUpdatingLocation]; } but it didn't help. I think there's something more to it
  • paxx
    paxx almost 13 years
    tried it.. i used if ([CLLocationManager locationServicesEnabled]) { [self.locManager startUpdatingLocation]; } but it didn't help. I think there's something more to it
  • paxx
    paxx almost 13 years
    tried it.. and i got a fishy CLLocationManager is <CLLocationManager: 0x4c41210>.. i think there's something more to it.. maybe locationFramework on my computer isn't installed properly.. do u know of any projects, or do u have and project that uses locationManager and works 100%.. i wanna test if it's my code or maybe something else.. btw: tnx for alloc thing.. did not know that.. used to be a .NET coder so i'm still trying to adapt to no garbage collector environment
  • Nik Burns
    Nik Burns almost 13 years
    the corelocation framework is definitely added to your build?
  • Rayfleck
    Rayfleck almost 13 years
    What did the NSLog statement say? Are your loc services enabled or not? The if statement will not enable them if they're disabled - you have to do that in the Settings app.
  • paxx
    paxx almost 13 years
    yes.. it wouldnt run without it
  • paxx
    paxx almost 13 years
    service is enabled.. but i'm running on simulator, and i'm not sure does running on simulator call any of the delegates.. i guess it should at least call error delegate
  • paxx
    paxx almost 13 years
    i'm using a simulator because i don't have my own developers acc.. but i'm gonna try it on friends acc today to see what happens on device.. but i'm confused in one thing.. shouldn't it at least call an error delegate on simulator? or is it normal that on simulator nothing happens???
  • idz
    idz almost 13 years
    @paki In my version of the simulator, 4.2, it does call out correctly (although you only get a few updates). I do not recall what happened in earlier versions.
  • Rayfleck
    Rayfleck almost 13 years
    Yes, the simulator does GPS callbacks to the delegate. At this point, I'd do a clean and rebuild, and make sure you do IOS Simulator / Reset Content and Settings... to make sure something funky isn't cached.
  • heMac
    heMac about 11 years
    This fix works for me.
  • Tim Bodeit
    Tim Bodeit over 10 years
    Perfect. Fixed it for me. I already tried this earlier, but only ensured it for the startUpdatingLocation method. Actually, the alloc/init etc has to be on the main thread as well!
  • Duncan C
    Duncan C over 10 years
    No. After adding a view controller's view to a window its VIEW gets retained, but not the view itself. This is an old post, but still worth commenting on. Releasing a view controller that's on-screen will likely cause a crash when anything that happens (like a button tap) tries to call one of the methods of the view controller.
  • jcady
    jcady over 8 years
    The answer! Instantiating the CLLocationManager on a separate queue from the main thread was my problem. Dispatching the call to the main thread fixed it.
  • mfaani
    mfaani almost 7 years
    @TimBodeit This certainly fixed the issue for me. But what I don't understand is previously I had it called from viewDidLoad. Isn't viewDidLoad being ran from main thread?