делегат возвращает ноль после вызова его в классе

#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:

  1. Убедитесь, что ваш контроллер все еще находится в памяти
  2. Вам не нужно использовать 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])
}
  
  1. Убедитесь, что func locationManager(_:didUpdateLocations) вызывается после установки делегата.
  2. В будущем вы хотите передать последнее местоположение при изменении делегирования как:
 weak var delegate :LocationUpdateProtocol? {
    didSet { 
        guard let last = currentLocation else { return }
        delegate?.locationDidUpdateToLocation(location: last)
    }
}
  
  1. Поскольку это синглтон только с 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. вы внесли изменения, как я предложил