Не удается выделить CLLocationManager

В моем UIViewController initWithNibNameOrNil я вызываю:

locationManager = [CLLocationManager new];

чтобы создать объект, затем позже в viewDidAppear я вызываю:

[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];

Но я никогда не получаю обновления местоположения; менеджер местоположения никогда не начинает обновлять местоположение. Но если я заменю ту же строку initWithNibNameOrNil на:

locationManager = [[myAppDelegate appDelegate] locationManager];

все отлично работает, кроме случайных вылетов иногда при

locationManager.delegate = self;

задается в самой следующей строке после того, как менеджер местоположения установлен на уже выделенный менеджер в делегате приложения. Ничто из этого не имеет для меня смысла; Я не понимаю, почему одно отличается от другого, а тем более почему ни один из них не работает последовательно. Может кто-нибудь просветить меня?

Обзор:

Способ 1 (не работает):

В 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];
}

Примечания. При использовании этого метода создания менеджера местоположения службы определения местоположения никогда не включаются после вызова startUpdatingLocation в viewDidAppear, поэтому никакие обновления местоположения никогда не получаются.


Способ 2 (в основном работает):

В 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
}

В 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];
}

Примечания: этот метод распределения работает, за исключением того, что если я нажимаю MapView, затем выталкиваю его, снова нажимаю, снова выталкиваю, затем снова пытаюсь нажать, я получаю сбой каждый раз на строке в initWithNib ... где я установил делегата на себя; NSZombieEnabled говорит:

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

Интересно...

NSLog(@"%s: %@; %@", PRETTY_FUNCTION, self, locationManager) говорит следующее:

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

Способ 3 (работает везде):

В 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];
}

Примечания: все выделение и настройка выполняются в viewDidAppear, и я не получаю никаких сбоев после повторного нажатия/выталкивания контроллера представления. Это здорово, но мне не нравится выделение в viewDidAppear, потому что приложение отстает всего на мгновение, потому что (я думаю) выделение locationManager забивает основной поток на это время. Я просто действительно не понимаю, почему метод 1 вообще не работает, метод 2 вылетает, а метод 3 работает. Разве все они не делают более или менее одно и то же?

Извините за весь код и поздравляю всех, кто прошел весь этот лабиринт вопросов! :)


person eric.mitchell    schedule 11.12.2011    source источник
comment
Добавьте этот оператор журнала сразу после вызова [CLLocation new] и непосредственно перед запросом startUpdatingLocation: NSLog("%s: %@; %@", __PRETTY_FUNCTION__, self, locationManager), а затем скопируйте/вставьте результаты в свой вопрос.   -  person Firoze Lafeer    schedule 11.12.2011
comment
Так вроде код изменился? Раньше вы делали [CLLocationManager new] в файле init. Теперь это в viewDidAppear, но, похоже, вы сейчас не устанавливаете делегата.   -  person Firoze Lafeer    schedule 11.12.2011
comment
Да, код изменился. [CLLocationManager new] в init не дал никакого эффекта, но добавление его в viewDidAppear действительно работает. Я случайно пропустил строку, в которой я устанавливаю делегата, убирая метод для краткости. Я публикую отчет о том, работает ли / не работает в вопросе сейчас.   -  person eric.mitchell    schedule 11.12.2011
comment
Можете ли вы добавить журналы к методу 2? Я полагаю, вы добавили их только в метод 3. Один из журналов должен быть в методе init.   -  person Firoze Lafeer    schedule 12.12.2011
comment
Пожалуйста, добавьте журнал как в init, так и в viewDidAppear для метода 2. Это то, что мы пытались сравнить.   -  person Firoze Lafeer    schedule 12.12.2011
comment
Проблема исчезла, хотя я не совсем уверен, почему. Код в методе 1 теперь работает как надо. Я не совсем уверен, что я изменил, чтобы заставить его работать...   -  person eric.mitchell    schedule 12.12.2011
comment
Я обновлю ответ, как только выясню, что я сделал, чтобы исправить это.   -  person eric.mitchell    schedule 12.12.2011
comment
Что ж, в том-то и беда, что не следует систематическому подходу к отладке проблемы. Иногда вы можете исправить это, не зная почему, а затем в будущем возникает аналогичная проблема, и вы до сих пор не знаете, почему. Думаю, у меня есть представление о том, что именно здесь происходило, но это невозможно проверить без надлежащего ведения журнала.   -  person Firoze Lafeer    schedule 12.12.2011
comment
Какова ваша идея? Я мог бы подтвердить это.   -  person eric.mitchell    schedule 12.12.2011


Ответы (3)


Пытаться:

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

вместо нового. Вы уверены, что назначаете делегата как самого себя? В противном случае ваш класс не будет прослушивать обновления местоположения.

person Bani Uppal    schedule 11.12.2011
comment
Я на 100% уверен. единственная строка, которую я изменяю, это locationManager = [CLLocationManager new]; to locationManager = [[myAppDelegate appDelegate] locationManager]; - person eric.mitchell; 11.12.2011
comment
Изменение на [[CLLocationManager alloc] init] имеет тот же эффект, что и [CLLocationManager new] — при вызове startUpdatingLocation ничего не происходит. - person eric.mitchell; 11.12.2011

Оказывается, виновником был, казалось бы, невинный фрагмент кода, который отключал менеджер местоположений, как только он запускался. Единственная причина, по которой я это увидел, заключалась в том, что я сравнил проект с недавней резервной копией и заметил разницу. Еще одна проблема решена благодаря резервному копированию!

person eric.mitchell    schedule 04.01.2012
comment
Не могли бы вы сообщить мне, что отключает диспетчер местоположений. Я застрял с той же проблемой. Спасибо. - person Arunabh Das; 06.08.2012

Осторожнее с определением менеджера местоположения. При использовании ARC может случиться так, что ваш экземпляр диспетчера местоположений будет удален.

person leviathan    schedule 21.02.2013