【问题标题】:SWIFT - LocationManager looping through multiple times?SWIFT - LocationManager 循环多次?
【发布时间】:2016-03-06 03:34:48
【问题描述】:

我有一个 locationManager 函数来获取用户的当前位置并发布城市和州的名称。我有一个打印语句,因此我可以在控制台中检查一切是否正常……确实如此。但是,它会打印 3 次城市位置。这实际上会导致我的实际应用出现问题,但这超出了这个问题的重点。

我的功能如下:

var usersLocation: String!

var locationManager: CLLocationManager!

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

    let userLocation: CLLocation = locations[0]


    CLGeocoder().reverseGeocodeLocation(userLocation) { (placemarks, error) -> Void in

        if error != nil {

            print(error)

        } else {

            let p = placemarks?.first // ".first" returns the first element in the collection, or nil if its empty
            // this code above will equal the first element in the placemarks array

            let city = p?.locality != nil ? p?.locality : ""
            let state = p?.administrativeArea != nil ? p?.administrativeArea : ""

            self.navigationBar.title = ("\(city!), \(state!)")
            self.usersLocation = ("\(city!), \(state!)")
            self.locationManager.stopUpdatingLocation()
            print(self.usersLocation)
            self.refreshPosts()
        }
    }
}

所以在我的 print(self.usersLocation) 中,它将在我的控制台中打印三遍。这正常吗?


更新以显示 VIEWDIDLOAD


override func viewDidLoad() {
    super.viewDidLoad()

    locationManager = CLLocationManager()
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestWhenInUseAuthorization()
    locationManager.startUpdatingLocation()

    self.tableView.rowHeight = UITableViewAutomaticDimension
    self.tableView.estimatedRowHeight = 250.0
}

【问题讨论】:

  • 你有一个调试器。调试!在您的print 语句中放置一个断点,以便您每次都停在那里。现在您可以查看 调用堆栈 并了解为什么要调用您的 didUpdateLocations
  • @matt 我应该提到我在编码方面是一个完全的菜鸟。我了解如何设置断点以使其停止,但是在哪里可以找到此调用堆栈并开始调试此问题?谢谢。
  • 当你命中断点时,你会在调试导航器中看到调用堆栈。

标签: ios swift locationmanager reversegeocodelocation


【解决方案1】:

我首先建议几点:

  1. 在执行reverseGeocodeLocation之前,请致电stopUpdatingLocation

    您在 reverseGeocodeLocation 完成处理程序闭包内调用 stopUpdatingLocation。问题在于这是异步运行的,因此didUpdateLocations 可能会在此期间收到额外的位置更新。通常,当您第一次启动定位服务时,您会收到许多更新,而且准确性通常会越来越高(例如,horizontalAccuracy 的值越来越小)。如果您在发起异步地理编码请求之前关闭位置服务,您将最大限度地减少此问题。

  2. 您还可以在viewDidLoad 中添加一个distanceFilter,这样可以最大限度地减少对委托方法的冗余调用:

    locationManager.distanceFilter = 1000
    
  3. 您可以使用自己的状态变量来检查反向地理编码过程是否已启动。例如:

    private var didPerformGeocode = false
    
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // if we don't have a valid location, exit
    
        guard let location = locations.first where location.horizontalAccuracy >= 0 else { return }
    
        // or if we have already searched, return
    
        guard !didPerformGeocode else { return }
    
        // otherwise, update state variable, stop location services and start geocode
    
        didPerformGeocode = true
        locationManager.stopUpdatingLocation()
    
        CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in
            let placemark = placemarks?.first
    
            // if there's an error or no placemark, then exit
    
            guard error == nil && placemark != nil else {
                print(error)
                return
            }
    
            let city = placemark?.locality ?? ""
            let state = placemark?.administrativeArea ?? ""
    
            self.navigationBar.title = ("\(city), \(state)")
            self.usersLocation = ("\(city), \(state)")
            print(self.usersLocation)
            self.refreshPosts()
        }
    }
    

【讨论】:

  • 谢谢 Rob,非常感谢。我从来没有意识到这是我的代码的异步情况。
  • 嗨 Rob,我只是将我的 stopUpdatingLocation 移到了我的 reverseGeocodeLocation 上方,但是在我离开该视图控制器并返回到它之后,它仍然会输出城市 3 次。例如,在启动应用程序时,它会很好地加载。但是,一旦我单击另一个视图控制器的按钮然后返回我的主页,它将再次输出城市 3 次...有什么解决此问题的建议吗?
  • 我还更新了我的viewDidLoad,如果这对我的案子有帮助的话!谢谢
  • 我对这种行为有点惊讶(你是说你看到didUpdateLocations 在你调用stopUpdatingLocation 之后继续被调用......这很令人惊讶,因为我看到了很多人实现了这种模式),但是添加你自己的状态变量来确定你是否已经启动了地理编码过程可能会解决这个问题。
  • @Matty - 我收回这一点:我确实看到didUpdateLocations 被叫了三次,就像你一样。我通常不这样做,因为我通常使用非零 locationManager.distanceFilter 来防止这些冗余更新。就调用堆栈的检查而言(这通常是一种追踪崩溃的技术,但这似乎不是问题所在)。但是,如果您想查看viewDidLoaddidUpdateLocations 被调用的频率,只需在其中添加print 语句即可。无论如何,请参阅修改后的答案,以澄清我的一些发现。
【解决方案2】:

我遇到了同样的问题,而 Rob 的回答对我没有帮助。

位置服务第一次启动时,位置会被多次更新,与距离过滤器无关。

您可能仍希望更新位置并且您不想丢失位置准确性(这是在启动时多次更新位置的全部要点),因此调用 stopUpdatingLocation(或使用局部变量)在第一次地理定位呼叫之后也不可行。

最直观的方法是将您的地理编码调用包装在 @objc 函数中,并延迟调用该函数:

NSObject.cancelPreviousPerformRequests(withTarget: self)
perform(#selector(myGeocodeFunction(_:)), with: location, afterDelay: 0.5)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多