Защо LocationManager didUpdateLocation не работи?

С CoreLocation.Foundation, добавен към BuildPhase и импортиран в горната част на файла, мога да получа информация за местоположението, ако поставя следното в контролер за изглед с бутон:

@IBAction func locationButton(sender: AnyObject) {
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestWhenInUseAuthorization()
    locationManager.startUpdatingLocation()
}

Продължава към locationManager didUpdateLocations с CLGeocoder().reverseGeocodeLocation completionHandler, който показва информацията за местоположението в друга функция - това работи.

НО не работи, когато се опитвам да прехвърля същия този код в моя модел на данни. Настроих модела със следното:

import CoreLocation

class Record: NSObject, CLLocationManagerDelegate
{
    let locationManager = CLLocationManager()

Тъй като няма бутон, поставих кода на LocationManager в:

        override init()
{
    iD = NSUUID().UUIDString

    super.init()

    if (CLLocationManager.locationServicesEnabled())
    {
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()

        switch CLLocationManager.authorizationStatus() {
        case .AuthorizedWhenInUse, .AuthorizedAlways:
            locationManager.startUpdatingLocation()
        case .NotDetermined:
            locationManager.requestWhenInUseAuthorization() // or request always if you need it
        case .Restricted, .Denied:
            print("tell users that they need to enable access in settings")
        default:
            break
        }
        print("Location services available")
        if CLLocationManager.authorizationStatus() == .NotDetermined
        {
            print("Still Not Determined")
        }
    } else { print("Location services not available") }

}

Получавам „Налични услуги за местоположение“. Но следният код никога не отпечатва нищо в конзолата, нито извиква функцията toSetLocationStamped.

func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
{
    print("started location man")
    CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler:        //pass the location co-ordinates
        {
            (placemarks, error) -> Void in

            if (error != nil)
            {
                println("Reverse geocoder failed with error" + error.localizedDescription)
                return
            }

            if placemarks.count > 0         //process the location array (placemarks)
            {
                let pm = placemarks[0] as! CLPlacemark
                self.toSetLocationStamped(pm)
                print("got here")
            } else
            {
                println("Problem receiving data from geocoder")
            }
    })
}

Ако поставя deinit на класа Record, с прост журнал за печат, няма изход.

deinit
{
    print("deinit")
}

Инициализирам dummyRecord: Запис от необходим init в клас MasterViewController:

class MasterViewController: UITableViewController
{
var records = [Record]()
var subjectDescription: String?

// weak var delegate: MonsterSelectionDelegate?        // property for object conforming to MSDelegate

required init(coder aDecoder: NSCoder)      //      // coder because class is loaded from Storyboard
{
    super.init(coder: aDecoder)

    var dummyRecord1 = Record()
    dummyRecord1.details = "All was very good and strong with a little bit of lemon on the side of the hill."
    dummyRecord1.dateTimeEntered = NSDate(dateString: "2015-07-22")
    dummyRecord1.subject = "Clouds"
    dummyRecord1.locationEntered = "Drittelsgasse 1, 69493 Großsachsen, Germany."
    dummyRecord1.photos.append(UIImage(named: "zombies.jpg")!)

    records.append(dummyRecord1)
}

person DrWhat    schedule 18.08.2015    source източник
comment
възможен дубликат на CLLocationManager didUpdateLocations не се извиква   -  person Anbu.Karthik    schedule 18.08.2015
comment
Как създавате екземпляр на този обект и държите ли препратка, така че да не се освобождава?   -  person Paulw11    schedule 18.08.2015
comment
Опитайте да поставите кода в метода init между главния блок на нишката. Веднъж имах такъв проблем.   -  person Abhi    schedule 18.08.2015
comment
От гледна точка на Paulw11, може да искате да приложите метод deinit, който регистрира, когато този обект бъде освободен, за да сте сигурни, че няма да бъде освободен, преди да е извършено асинхронното извикване.   -  person Rob    schedule 18.08.2015
comment
Актуализирах въпроса, опитвайки се да отговоря на коментарите - особено Paulw и Rob. Не мисля, че е дубликат на другия въпрос и ако е, бихте ли обяснили как да зададете NSLocationAlwaysUsageDescription (за точка 1); и за точка 3 наистина бих искал да видя стойността, зададена в модела, а не извикана на ниво контролер на изгледа (не е ли това MVC или го прекалявам).   -  person DrWhat    schedule 19.08.2015
comment
@Abhi, съжалявам, но не съм сигурен какво имаш предвид да поставиш кода вътре в метода init между главния блок на нишката. Тъй като това е модел, а не изглед, който ще се зареди или е заредил (и т.н.), не виждам къде другаде мога да го пусна.   -  person DrWhat    schedule 19.08.2015
comment
Ако видите налични услуги за местоположение, всичко това означава, че сте поискали услуги за местоположение, а не че е предоставено. напр. може да не е разрешено, ако преди това е било отказано или ако не сте успели да зададете NSLocationWhenInUseUsageDescription в Info.plist. Може да предложа да проверите authorizationStatus на мениджъра на местоположението и да внедрите didChangeAuthorizationStatus и да видите дали виждате, че се оторизира. Не е свързано, но ми се струва неефективно всеки запис да има свой собствен CLLocationManager. Изглежда, че това не трябва да присъства в модела, още по-малко на рекордното ниво.   -  person Rob    schedule 19.08.2015
comment
Опитах се да проверя с authorizationStatus, но това просто върна „(Enum Value)“. От документите на Apple опитах locationServicesEnabled() и отпечатах „true“ на конзолата. По отношение на ефективността, записът е до голяма степен самостоятелна единица. Малко вероятно е потребителят да създаде повече от един запис за случай на употреба и услугите за местоположение не се изискват никъде другаде. Има ли смисъл тогава?   -  person DrWhat    schedule 20.08.2015
comment
Относно authorizationStatus, има само четири възможни стойности, така че добавете израз if/switch, за да видите коя е тя. Re locationServicesEnabled, да, трябва да го направите, но това е съвсем различен въпрос (напр. това устройство с GPS възможности ли е). Трябва да проверите authorizationStatus, за да видите дали потребителят е дал разрешение. Отново мениджър на местоположения в записа, това е вашето решение, но това е архитектурно грешното място. Плюс това, ако наистина не е масив, тогава не го правете масив. И ако е масив, поставянето на диспечера на местоположението там е определено грешното място.   -  person Rob    schedule 20.08.2015
comment
AuthorizationStatus не е определен! Мислех, че ще пита автоматично. Прочетох, че трябва да извикам requestWhenInUseAuthorization() или requestAlwaysAuthorization(), но това (вижте редактирания код по-горе) не изисква оторизация, нито променя моя AuthorizationStatus. Не знам дали е необходимо, но имам низ в requestWhenInUseAuthorization() в plist.   -  person DrWhat    schedule 20.08.2015
comment
@Rob, къде мога да превърна мениджъра на местоположения в масив? Не е необходимо да е масив - само едно място, където е създаден записът, е всичко, което искам.   -  person DrWhat    schedule 21.08.2015
comment
Може би ви разбрах погрешно: мислех, че имате масив от записи и правите мениджъра на местоположението свойство на всеки запис, като по този начин завършвате с множество мениджъри на местоположение. Ако не съм разбрал, моля за извинение.   -  person Rob    schedule 21.08.2015
comment
Не, записът е самостоятелен обект с местоположение като едно от неговите свойства (зададено при иницииране, може би проверено при деиницииране, но в противен случай мога да го изключа). Очаквам потребителят да създаде само един запис за случай на употреба. Има причини, поради които го виждам като част от модела. Оценявам вашите коментари - карате ме да задавам въпроси и да науча купища неща по тази тема.   -  person DrWhat    schedule 21.08.2015


Отговори (1)


След като се обадиш

self.locationManager.requestWhenInUseAuthorization()

не можете веднага да започнете да актуализирате местоположението. Това повикване е асинхронно.

Ето как трябва да го направите правилно:

1) Проверете състоянието на оторизацията:

switch CLLocationManager.authorizationStatus() {
    case .AuthorizedWhenInUse, .AuthorisedAlways:
        locationManager.startUpdatingLocation()
    case .NotDetermined:
        locationManager.requestWhenInUseAuthorization() // or request always if you need it
    case .Restricted, .Denied:
        // tell users that they need to enable access in settings
    default:
        break
}

2) Ако преди това сте упълномощили приложението си, това трябва да актуализира местоположението. Ако обаче не сте го направили, ще се появи изскачащ прозорец. За да отговорите на промяната в статуса на оторизация, трябва да добавите друга функция:

func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    if (status == .AuthorizedAlways) || (status == .AuthorizedWhenInUse) {
        locationManager.startUpdatingLocation()
    }
}
person Andriy Gordiychuk    schedule 20.08.2015
comment
Това има смисъл. Опитах това, което мисля, че имате предвид, и актуализирах въпроса си - вижте инициализацията за отмяна. Но, за съжаление, все още не иска да разреши услуги за местоположение и все още не навлизам в метода didUpdateLocations. И ако проверя CLLocationManager.authorizationStatus() == .NotDetermined в края на инициализацията на отмяната, той все още оценява true. Наистина трябва да правя нещо изостанало. - person DrWhat; 20.08.2015
comment
Ааа - но аз влизам в didChangeAuthorisationStatus, но изразът if (.AuthorizedAlways или ..WhenInUse) не оценява true... - person DrWhat; 20.08.2015
comment
@DrWhat, ако не получите изскачащ прозорец с молба за предоставяне на достъп до местоположението, това означава, че сте деактивирали достъпа до местоположението. То е деактивирано глобално или за това конкретно приложение. Получавате това изскачащо меню само веднъж и ако потребителят натисне НЕ, не можете да попитате отново - той трябва ръчно да го включи в настройките за местоположение. Отидете в Settings -› Privacy -› Location Services и се уверете, че те са активирани както глобално, така и за вашето приложение - person Andriy Gordiychuk; 20.08.2015
comment
Мисля, че си прав, защото изпробвах кода ти в друг проект и той работи страхотно. НО, ако отида в настройките на симулатора, глобалната настройка е включена. Ако щракна върху System Services от там обаче, целият симулатор замръзва (не може да продължи напред, не може да се върне назад). Имам достъп до менютата извън „телефона“, но трябва да затворя целия симулатор, за да направя нещо на действителния телефон. Предполагам, че в системните услуги ще бъде настройката на приложението ми (?). - person DrWhat; 21.08.2015
comment
@DrWhat просто изтрийте приложението си от симулатора и го инсталирайте отново :) - person Andriy Gordiychuk; 21.08.2015
comment
Няма промяна. Все още не е определено, няма изскачащо предупреждение, в didChangeAuth.., но не е разрешено и все още замръзва, ако се опитам да вляза в системните услуги. - person DrWhat; 21.08.2015
comment
@DrWhat аааааа, забравих! Трябва да добавите NSLocationWhenInUseUsageDescription и/или NSLocationAlwaysUsageDescription ключ към вашия Info plist файл. Иначе няма да стане :) - person Andriy Gordiychuk; 21.08.2015
comment
Не знам дали това е уместно, но е странно, че когато стартирам другото приложение с услуги за местоположение, наречено app2, мога да видя други приложения, които съм изпълнявал наскоро, включително приложението, където услугите за местоположение не се актуализират, app1. В настройката за услуги за местоположение виждам приложение 2 (с лилава стрелка) и друго приложение, но не и приложение 1, където услугите за местоположение не се актуализират. Работещо приложение1, където услугите за местоположение не се актуализират, това е единственото приложение, което виждам в симулатора, и не мога да го видя в настройките на услугите за местоположение. - person DrWhat; 21.08.2015
comment
@DrWhat Нека продължим тази дискусия в чата. - person Andriy Gordiychuk; 21.08.2015
comment
УРА!!! Имах requestWhenInUseAuthorization() в plist, а не NS... Главата ме боли, но по-малко, отколкото преди няколко минути. - person DrWhat; 21.08.2015