SWIFT - LocationManager循环多次?

时间:2015-12-02 01:40:51

标签: ios swift locationmanager reversegeocodelocation

我有一个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)中,它将在我的控制台中打印三次。这是正常的吗?

更新显示视图

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
}

2 个答案:

答案 0 :(得分:6)

我首先提出一些建议:

  1. 在执行stopUpdatingLocation之前致电reverseGeocodeLocation

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

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

    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()
        }
    }
    

答案 1 :(得分:0)

我遇到了同样的问题,Rob的回答并没有为我做。

当位置服务首次启动时,无论distanceFilter如何,该位置都会多次更新。

您可能仍希望更新位置,并且您不希望失去位置准确性(这是在启动时多次更新位置的全部内容),因此请调用stopUpdatingLocation(或使用本地变量)在第一次地理定位呼叫之后也没有。

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

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