Как получить текущие координаты пользователя на Swift (CLLocationManager)?
Проблема: асинхронность и отсутствие обработки делегата
Ваш код не работает, потому что locationManager.location — это последнее известное местоположение, которое может быть nil, если менеджер еще не успел получить данные. Вызов startUpdatingLocation() запускает асинхронный процесс, и результат приходит в метод делегата didUpdateLocations. Вы пытаетесь прочитать координаты сразу после запуска, но система еще не успела их определить.
Правильное решение (пошагово)
- Запросить разрешение — вызываем
requestWhenInUseAuthorization(). - Реализовать делегат — подписаться на протокол
CLLocationManagerDelegate. - Обработать результат — в методе
didUpdateLocationsполучить массив объектовCLLocation. - Остановить обновления — после получения координат вызвать
stopUpdatingLocation(), чтобы сберечь батарею.
Исправленный код
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
// MARK: - CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
// Координаты получены
let latitude = location.coordinate.latitude
let longitude = location.coordinate.longitude
print("Latitude: \(latitude), Longitude: \(longitude)")
// Останавливаем обновления, чтобы не тратить заряд
manager.stopUpdatingLocation()
// Теперь можно отправить на сервер или использовать в UI
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Ошибка получения локации: \(error.localizedDescription)")
}
}
Важные пояснения
- desiredAccuracy — задает точность.
kCLLocationAccuracyBest— максимальная, но требует больше времени и энергии. Для большинства задач хватитkCLLocationAccuracyNearestTenMeters. - locations.last — массив содержит несколько точек, последняя — самая свежая.
- didFailWithError — обязательно реализуйте этот метод, иначе не узнаете об ошибках (например, отключен GPS).
- Симулятор — не забудьте задать кастомную локацию через меню Features → Location. Если не задать, координаты будут nil.
Дополнительно: проверка авторизации
Иногда пользователь запрещает доступ. Проверьте статус:
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .authorizedWhenInUse, .authorizedAlways:
manager.startUpdatingLocation()
case .denied, .restricted:
print("Доступ к геолокации запрещен")
default:
break
}
}
Итог
Главная ошибка — синхронное чтение locationManager.location. Всегда используйте делегат didUpdateLocations для получения координат. Не забывайте про stopUpdatingLocation() после получения результата.
Альтернативный подход: использование одноразового запроса
Если вам нужно получить координаты только один раз (например, при нажатии кнопки), можно использовать метод requestLocation() вместо startUpdatingLocation(). Он автоматически останавливает обновления после получения результата и лучше подходит для простых сценариев.
import CoreLocation
class LocationManager: NSObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
var completion: ((CLLocation?, Error?) -> Void)?
override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
}
func fetchLocation(completion: @escaping (CLLocation?, Error?) -> Void) {
self.completion = completion
manager.requestWhenInUseAuthorization()
manager.requestLocation()
}
// MARK: - Delegate
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
completion?(locations.last, nil)
completion = nil
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
completion?(nil, error)
completion = nil
}
}
Плюсы:
- Не нужно вручную вызывать
stopUpdatingLocation(). - Однократный запрос — экономит батарею.
- Удобно для кнопки "Показать мое местоположение".
Минусы:
- Не подходит для отслеживания движения (например, навигация).
- В симуляторе может вернуть ошибку, если не задана локация.
Используйте этот способ, если вам нужно "разово" узнать, где находится пользователь.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги