#swift #delegates #location-services
#swift #делегаты #службы определения местоположения
Вопрос:
Я использую этот класс, чтобы получить местоположение и отправить его с делегатом другому контроллеру представления, но делегат возвращает nil при вызове. мой класс:
protocol LocationUpdateProtocol {
func locationDidUpdateToLocation(location : CLLocation)
}
/// Notification on update of location. UserInfo contains CLLocation for key "location"
let kLocationDidChangeNotification = "LocationDidChangeNotification"
class LocationServiceHelper:NSObject,CLLocationManagerDelegate {
static let sharedManager = LocationServiceHelper()
private let locationManager = CLLocationManager()
var currentLocation:CLLocation?
weak var delegate :LocationUpdateProtocol?
private override init() {
super.init()
self.locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLLocationAccuracyHundredMeters
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
// MARK: CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let delegate = self.delegate else {
return
}
currentLocation = locations.first
let userInfo:NSDictionary = ["location":currentLocation!]
delegate.locationDidUpdateToLocation(location: currentLocation!)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: kLocationDidChangeNotification), object: self, userInfo: userInfo as? [AnyHashable : Any])
}
}
Я вызвал делегата в другом классе ниже:
var locationServiceReference = LocationServiceHelper.sharedManager
override func viewDidLoad() {
super.viewDidLoad()
fillFields()
locationServiceReference.delegate = self
self.mapView.showsUserLocation = true
}
func locationDidUpdateToLocation(location: CLLocation) {
// print(location)
// let myLocation = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let myLocationForTesting = CLLocationCoordinate2D(latitude: 33.410165, longitude: 35.480060)
myLocation = location
let region = MKCoordinateRegion(center: myLocationForTesting, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.mapView.setRegion(region, animated: true)
}
в расположении did update делегат возвращает nil, есть идеи, что происходит? функция не была вызвана, так как делегат возвращает nil .
Комментарии:
1. Что вы добавили
LocationUpdateProtocol
? Добавьте этот код тоже.2. он находится в этом классе, вверху
3. Я имел в виду, где вы хотите, чтобы
LocationUpdateProtocol delegate
должно быть вызвано? Нравится, где вы инициализировалиLocationServiceHelper
?4. выполнено, вопрос обновлен
5. Проверьте мой ответ ниже.
Ответ №1:
- Убедитесь, что ваш контроллер все еще находится в памяти
- Вам не нужно использовать guard. Необязательная цепочка работает лучше в таких случаях:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
currentLocation = locations.first
let userInfo:NSDictionary = ["location":currentLocation!]
delegate?.locationDidUpdateToLocation(location: currentLocation!)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: kLocationDidChangeNotification), object: self, userInfo: userInfo as? [AnyHashable : Any])
}
- Убедитесь, что
func locationManager(_:didUpdateLocations)
вызывается после установки делегата. - В будущем вы хотите передать последнее местоположение при изменении делегирования как:
weak var delegate :LocationUpdateProtocol? {
didSet {
guard let last = currentLocation else { return }
delegate?.locationDidUpdateToLocation(location: last)
}
}
- Поскольку это синглтон только с 1 делегатом, убедитесь, что вы не устанавливаете значение delegate для
nil
или другого объекта с коротким сроком службы где-либо еще
Комментарии:
1. не сработало, делегат по-прежнему возвращает nil, сбой не произошел, но функция не была вызвана, потому что делегат по-прежнему равен нулю
2. Я получаю сообщение об ошибке: weak не должен применяться к LocationUpdateProtocol, не привязанному к классу, рассмотрите возможность добавления соответствия протоколу, привязанного к классу
3. @MrJ измените объявление протокола на
protocol LocationUpdateProtocol: AnyObject {
4. Итак, сделайте это.
protocol LocationUpdateProtocol : class
5. @matt
class
будет устаревшим в пользуAnyObject
. Так что лучше начните использовать его сейчас 🙂 forums.swift.org/t/class-only-protocols-class-vs-anyobject /…
Ответ №2:
Этот код —
var locationServiceReference = LocationServiceHelper.sharedManager
выполняется перед вашим delegate
набором, вот почему delegate
возвращает nil
всегда.
Заменить
var locationServiceReference = LocationServiceHelper.sharedManager
С
var locationServiceReference : LocationServiceHelper!
И инициализирует после viewDidLoad()
получения вызова.
override func viewDidLoad() {
super.viewDidLoad()
locationServiceReference = LocationServiceHelper.sharedManager
locationServiceReference.delegate = self
}
Надеюсь, это вас успокоит. Дайте мне знать, если у вас все еще возникают какие-либо проблемы.
Комментарии:
1. проблема в первом классе, где существует протокол, поскольку делегат остается нулевым, поэтому функция не будет вызвана, я попробовал ваше решение, но не сработало
2.
locationServiceReference.delegate = self
строка установитdelegate
в классе. В противном случаеdelegate
оставатьсяnil
всегда3. вы внесли изменения, как я предложил