Ошибка LocationManager, когда приложение просыпается для обновления

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

Мой код для обработки приложения просыпается для обновления местоположения на didFinishLaunchingWithOptions

 @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate { let locationManager = CLLocationManager() var glat : String = "" var glong : String = "" func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { if launchOptions?[UIApplicationLaunchOptionsLocationKey] != nil { let locationManager = CLLocationManager() //or without this line, both crashes locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest let status = CLLocationManager.authorizationStatus() if (status == CLAuthorizationStatus.AuthorizedAlways) { locationManager.startMonitoringSignificantLocationChanges() } } return true } 

Вот делегат locationmanager на AppDelegate

  func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { if let lat = manager.location?.coordinate.latitude, let long = manager.location?.coordinate.longitude { print(glat + " " + glong) glat = String(lat) glong = String(long) //Line 339 updateloc(String(lat), long: String(long)) } } 

Функция отправки информации о местоположении на сервер

 func updateloc(lat : String, long : String) { let session = NSURLSession.sharedSession() //Line 354 let request = NSMutableURLRequest(URL: NSURL(string: "URLTO/updateloc.php")!) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.HTTPMethod = "POST" let data = "lat=\(lat)&long=\(long)" request.HTTPBody = data.dataUsingEncoding(NSASCIIStringEncoding) let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in if let error = error { print(error) } if let response = response { let res = response as! NSHTTPURLResponse dispatch_async(dispatch_get_main_queue(), { if (res.statusCode >= 200 && res.statusCode < 300) { do{ let resultJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions()) var success = 0 if let dictJSON = resultJSON as? [String:AnyObject] { if let successInteger = dictJSON["success"] as? Int { success = successInteger if success == 1 { print("ok") } } else { print("no 'success' key in the dictionary, or 'success' was not compatible with Int") } } else { print("unknown JSON problem") } } catch _{ print("Received not-well-formatted JSON") } } }) } }) task.resume() } 

Вот краш-журнал

 Crashed: com.apple.main-thread 0 Jemiyet 0x10015d998 specialized AppDelegate.updateloc(String, long : String) -> () (AppDelegate.swift:354) 1 Jemiyet 0x10015ddf8 specialized AppDelegate.locationManager(CLLocationManager, didUpdateLocations : [CLLocation]) -> () (AppDelegate.swift:339) 2 Jemiyet 0x100159d0c @objc AppDelegate.locationManager(CLLocationManager, didUpdateLocations : [CLLocation]) -> () (AppDelegate.swift) 3 CoreLocation 0x1893d08b8 (null) + 21836 4 CoreLocation 0x1893ccaac (null) + 5952 5 CoreLocation 0x1893c6e48 (null) + 880 6 CoreFoundation 0x18262cf84 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 20 7 CoreFoundation 0x18262c8bc __CFRunLoopDoBlocks + 308 8 CoreFoundation 0x18262ad04 __CFRunLoopRun + 1960 9 CoreFoundation 0x182554c50 CFRunLoopRunSpecific + 384 10 GraphicsServices 0x183e3c088 GSEventRunModal + 180 11 UIKit 0x18783e088 UIApplicationMain + 204 12 Jemiyet 0x10015a324 main (AppDelegate.swift:20) 

Приложение аварийно завершает работу приложения при обновлении местоположения в режиме startMonitoringSignificantLocationChanges

Я действительно не вижу здесь никакой ошибки. Кто-нибудь может помочь мне исправить это?

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

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

startMonitoringSignificantLocationChanges пробудит ваше приложение в фоновом режиме, если оно включено, когда приложение завершит работу ОС.

В зависимости от того, что вы хотите достичь, вы можете подписаться на два разных события и начать останавливать соответствующую службу сервисов местоположений на событиях делегирования приложения.

В качестве широкого (снятого в темноте) примера:

 class LocationCommander { let locationManager = CLLocationManager() let defaultCenter = NSNotificationCenter.defaultCenter() //- NSUserDefaults - LocationServicesControl_KEY to be set to TRUE when user has enabled location services. let UserDefaults = NSUserDefaults.standardUserDefaults() let LocationServicesControl_KEY = "LocationServices" init(){ defaultCenter.addObserver(self, selector: #selector(self.appWillTerminate), name: UIApplicationWillTerminateNotification, object: nil) defaultCenter.addObserver(self, selector: #selector(self.appIsRelaunched), name: UIApplicationDidFinishLaunchingNotification, object: nil) } func appIsRelaunched (notification: NSNotification) { //- Stops Significant Location Changes services when app is relaunched self.locationManager.stopMonitoringSignificantLocationChanges() let ServicesEnabled = self.UserDefaults.boolForKey(self.LocationServicesControl_KEY) //- Re-Starts Standard Location Services if they have been enabled by the user if (ServicesEnabled) { self.updateLocation() } } func appWillTerminate (notification: NSNotification){ let ServicesEnabled = self.UserDefaults.boolForKey(self.LocationServicesControl_KEY) //- Stops Standard Location Services if they have been enabled if ServicesEnabled { self.locationManager.stopUpdatingLocation() //- Start Significant Location Changes to restart the app self.locationManager.startMonitoringSignificantLocationChanges() } NSUserDefaults.standardUserDefaults().synchronize() } func updateLocation () { if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.Authorized){ self.locationManager.desiredAccuracy = kCLLocationAccuracyBest self.locationManager.distanceFilter = kCLDistanceFilterNone self.locationManager.startUpdatingLocation() //- Save Location Services ENABLED to NSUserDefaults self.UserDefaults.setBool(true, forKey: self.LocationServicesControl_KEY) } else { //- Unauthorized, requests permissions } } } 

Имейте в виду, что этот код не был протестирован, я извлек сегменты старого проекта, которые могут иметь некоторые синтаксические ошибки из-за обновлений языка.

В целом мы это делаем:

  • Подпишитесь на соответствующие уведомления
  • Когда приложение вот-вот закончится, проверьте, получили ли мы обновления местоположения, если мы хотим, остановите стандартную службу и запустите службу значительных изменений, чтобы разбудить приложение, когда доступно новое обновление.
  • Когда приложение просыпается, оно уведомит класс, который решит, продолжаем ли мы отслеживать обновления уведомлений или нет (на основе значения, хранящегося в NSUserDefaults).

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

Надеюсь, это поможет!

В документации говорится:

Для служб, которые перезапускают приложение, система добавляет ключ UIApplicationLaunchOptionsLocationKey в словарь параметров, переданный делегату приложения во время запуска. Когда этот ключ присутствует, вы должны сразу же перезапустить службы своего приложения. Словарь параметров не включает информацию о самом событии местоположения. Вы должны настроить новый объект диспетчера местоположений и делегировать его и снова запустить свои службы определения местоположения для получения ожидающих событий.

Кроме того, он говорит:

Вызов этого метода [означает startMonitoringSignificantLocationChanges ] несколько раз подряд не приводит к автоматическому созданию новых генерируемых событий. Вызов stopMonitoringSignificantLocationChanges между ними, однако, вызывает новое начальное событие, которое будет отправлено при следующем вызове этого метода.

Это подразумевает больше, чем может быть ясно на первый взгляд. Во-первых, тот факт, что обновление местоположения вызвало перезагрузку вашего приложения, не означает, что вы сразу же получите его через locationManager:didUpdateLocations: делегата locationManager:didUpdateLocations: method. Во-вторых, если вы находитесь в фоновом режиме (и, таким образом, не перезапущены, а только стали активными!), Все по-другому . На самом деле, общая проблема, с которой я встречал людей, заключается в том, что они не знают, находятся ли они в фоновом режиме (неактивны) или завершены / просто перезапущены. Вы даже не можете легко проверить / увидеть это, потому что приложение, которое было прервано системой, все же появляется при одновременном нажатии кнопки «домой». Проверьте список, показанный в разделе Attach to Process... в меню Debug XCode, чтобы узнать, работает ли ваше приложение (и в фоновом режиме) или нет (кстати, завершение приложения с помощью кнопки Stop в XCode приводит к этой несогласованности, если вы хотите сыграть вокруг с различными способами вы можете стать активными или возобновить). Я просто упоминаю об этом здесь, потому что много вопросов спрашивают: «Как происходит X, когда мое приложение снова активируется?» и люди, отвечающие, принимают разные вещи, чем то, что подразумевал под этим человек.

В любом случае, если ваше приложение фактически было перезапущено, переменная locationManager теперь содержит новый экземпляр, и вы должны получить обновление сразу после вызова startMonitoringSignificantLocationChanges . Я дойду до проблемы, с которой вы все еще столкнетесь ниже. Если ваше приложение снова активизировалось, вы должны вызвать stopMonitoringSignificantLocationChanges , затем снова startMonitoringSignificantLocationChanges чтобы немедленно получить обновление (короче: всегда останавливать, а затем начинать правильно перезагружать, это не повредит, даже если вы еще не запускались).

Теперь к проблеме я думаю, что результаты (частично) от этого беспорядка с возможностью возобновления Apple после обновлений местоположения. Я не совсем уверен, что происходит, не играя с вашим кодом, но я надеюсь, что это поможет: В вашем application:didFinishLaunchingWithOptions: метод вы устанавливаете локальную константу с let locationManager = CLLocationManager() . Затем он перезапускается и запускает обновления местоположения. Тем не менее, он может быть освобожден до назначения locationManager:didUpdateLocations: делегата locationManager:didUpdateLocations: метод вызван, в конце концов, обратный вызов происходит асинхронно (и application:didFinishLaunchingWithOptions: может вернуться до того, как оно вызывается). Я понятия не имею, как и почему это работает, и насколько это возможно, возможно, это удача, или это связано с тем, как CLLocationManager работает на внутреннем уровне. В любом случае, то, что я думаю, происходит тогда, когда в locationManager:didUpdateLocations: вы больше не получаете значимых данных местоположения, потому что экземпляр CLLocationManager ответственный за вызов, уже недействителен. lat и long являются пустыми или даже нулевыми, а URL вашего запроса (который вы не показывали) недействителен.

Я бы предложил сначала:

  1. Убедитесь, что постоянный locationManager вашего класса правильно установлен в application:didFinishLaunchingWithOptions: (сразу после проверки наличия UIApplicationLaunchOptionsLocationKey ). Избавьтесь от локальной константы с тем же именем.
  2. Остановите и перезапустите обновления местоположения. Это должно вызвать locationManager:didUpdateLocations: вашего делегата locationManager:didUpdateLocations: метод немедленно с последними данными о местоположении (тот, который вызвал перезапуск приложения или снова стал активным).
  3. Убедитесь, что вы получаете значимые данные в своем locationManager:didUpdateLocations: method. Не вызывайте updateloc если это не так (вы также можете переместить print(glat + " " + glong) строки print(glat + " " + glong) после того, как вы установите переменные класса на новые значения, поэтому вы видите на консоли, что вы получаете имеет смысл).

Там одна маленькая вещь, которую я не могу сказать на макушке: Если ваше приложение снова активируется (и не перезапускается), я не уверен, что UIApplicationLaunchOptionsLocationKey даже настроен вообще. Вы можете исследовать это один, тоже. Если стать активным не является «повторным» в этом смысле, хотя ваш locationManager все равно будет рад работать в любом случае, по крайней мере, это то, что я получаю из документации (и прошло некоторое время с тех пор, как я пытался что я сам). Позвольте мне / нам знать, если у вас все еще есть проблемы, мне любопытно, как это получится. 🙂

Попробуй это

 dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_DEFAULT.rawValue), 0)) { updateloc(String(lat), long: String(long)) } 
  • swift - Тестирование модели CoreData (+ MagicalRecord) триггеров модели EXC_BAD_ACCESS
  • Swift - Почему в AFHTTPSManManager требуется init (coder)?
  • Swift, проверьте, имеет ли массив значение по индексу
  • Два UIPickerViews и различные комбинации приводят к разным фотографиям
  • Сохранение и удаление данных из CoreData с быстрой ошибкой _PFManagedObject_coerceValueForKeyWithDescription + 2864
  • Как включить ведение журнала рестайтов в быстром режиме
  • Как сделать диагональ UITableView в iOS с Swift?
  • Диапазон (0 ... 4) и substringWithRange?
  • Импортировать файл для модуля «Swift»: разрешение отклонено
  • Как выделить текст в строке, содержащей emojis в Swift?
  • Как установить Buck Build Facebook на существующий проект Xcode?
  • Interesting Posts

    – оба распознавателя равны нулю в отладчике

    Как заставить унаследованный класс иметь возможность видеть скрытые методы родителя в Objective-C

    Каталог активов UIImage ImageNamed: was nil

    Могу ли я создать статическую библиотеку для iOS без использования Xcode IDE?

    Физический движок iPhone для моделирования жидкости / воды?

    UIProgressView отображает проблемы в iOS 7

    Использование NSLayoutConstraints для выравнивания динамических представлений по вертикали в ScrollView с использованием Swift

    не может получать уведомление после публикации внутри соединенияDidFinishLoading :, метод делегирования NSURLConnection

    Objective-C XMPPFramework Оффлайн-очереди

    есть поддержка отмечать события как только для чтения либо в CalDAV, либо в ical (icalendar)

    Почему PFRelation не поддерживает запросыLocalDataStore?

    Как применять фильтры Core Image по одному для экономии памяти?

    Пользовательский подкласс UIView с XIB в Swift

    Как получить список задач в очереди GCD?

    Не удалось загрузить NIB в пакете CocoaPods

    Давайте будем гением компьютера.