Can't allocate CLLocationManager

梦想的初衷 提交于 2019-12-25 03:36:09

问题


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! :)


回答1:


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.




回答2:


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!




回答3:


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



来源:https://stackoverflow.com/questions/8462146/cant-allocate-cllocationmanager

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!