Can't allocate CLLocationManager

In my UIViewController's initWithNibNameOrNil , I call:

locationManager = [CLLocationManager new];

to create the object, then later in viewDidAppear I call:

[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];

But I never receive a location update; the location manager never starts updating the location. Yet if I replace that same line the initWithNibNameOrNil with:

locationManager = [[myAppDelegate appDelegate] locationManager];

everything works great, except for random crashes sometimes when

locationManager.delegate = self;

is set in the very next line after location manager is set to the already allocated manager in the app delegate. None of this makes sense to me; I don't understand why one is different from the other, much less why neither of them works consistently. Can someone please enlighten me?

Summary:

Method 1 (does not work):

In MapView.m :

initWithNibNameOrNil :

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if(self) {
        locationManager = [CLLocationManager new];
        locationManager.delegate = self;
        locationManager.distanceFilter = kCLHeadingFilterNone;
        locationManager.headingFilter = 3;

        if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull))
            locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
        else
            locationManager.desiredAccuracy = kCLLocationAccuracyBest;

        //more setup irrelevant to the question
    }
    return self;
}

viewDidAppear :

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:YES];
    [locationManager startUpdatingLocation];
    [locationManager startUpdatingHeading];
}

Notes: Using this method of creating the location manager, location services never get enabled after startUpdatingLocation is called in viewDidAppear and so no location updates are ever received.


Method 2 (does work, mostly):

In myAppDelegate.m :

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];

    self.locationManager = [CLLocationManager new];
    self.locationManager.distanceFilter = kCLHeadingFilterNone;
    self.locationManager.headingFilter = 3;

    if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull))
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    else
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;

    //more irrelevant setup
}

In MapView.m :

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if(self) {
        locationManager = [[Trail_TrackerAppDelegate appDelegate] locationManager];
        locationManager.delegate = self;
        //more irrelevant setup
    }
    return self;
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:YES];
    [locationManager startUpdatingLocation];
    [locationManager startUpdatingHeading];
}

Notes : this allocation method works, except if I push MapView, then pop it, push it again, pop it again, then try to push it again, I get a crash every time at the line in initWithNib... where I set the delegate to self; NSZombieEnabled says:

-[CLLocationManager setDelegate:]: message sent to deallocated instance 0x9540ad0

Interesting...

NSLog(@"%s: %@; %@", PRETTY_FUNCTION , self, locationManager) says this:

-[MapView initWithNibName:bundle:]: <MapView: 0x92ae3e0>; <CLLocationManager: 0x92a3560>

Method 3 (works all-around):

In MapView.m :

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:YES];
    locationManager = [CLLocationManager new];
    locationManager.delegate = self;
    locationManager.distanceFilter = kCLHeadingFilterNone;
    locationManager.headingFilter = 3;

    if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull))
        locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    else
        locationManager.desiredAccuracy = kCLLocationAccuracyBest;

    [locationManager startUpdatingLocation];
    [locationManager startUpdatingHeading];
}

Notes : all of the allocation and setup is done in viewDidAppear , and I don't get any crashes after repeated pushing/popping of the view controller. This is great, but I don't like allocating in viewDidAppear because the app lags for just a moment because (I think) the allocation of locationManager clogs up the main thread for that time. I just really don't understand why Method 1 doesn't work at all, Method 2 crashes, and Method 3 works. Don't they all do more-or-less the same thing?

Sorry for all the code, and congrats to anyone who made it all the way through this maze of a question! :)


Try:

locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];

instead of new. Are you sure you are assigning the delegate as self? Otherwise your class won't listen for location updates.


Turns out the culprit was a seemingly-innocent piece of code that was turning off the location manager as soon as it was being started. The only reason I saw it was because I compared the project to a recent backup, and noticed the difference. Another problem solved because of backing up!


Careful where you're defining your location manager. When using ARC, it could happen that your location manager instance gets discarded.

链接地址: http://www.djcxy.com/p/20342.html

上一篇: iPhone在后台使用CLLocationManager时强行杀死

下一篇: 无法分配CLLocationManager