SWIFT - LocationManager looping through multiple times?

家住魔仙堡 提交于 2019-11-28 09:45:53

问题


I have a locationManager function to grab the users current location and posting the name of the city and state. I have a print statement so I can check in my console if everything is working properly...and it is. However, it prints the city location 3 times. This actually causes an issue in my actual app but thats beyond the point of this question.

My function is as follows:

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

So in my print(self.usersLocation) it will print in my console three times. Is this normal?


UPDATE TO SHOW 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
}

回答1:


I'd first suggest a few things:

  1. Call stopUpdatingLocation before you perform reverseGeocodeLocation.

    You are calling stopUpdatingLocation inside the reverseGeocodeLocation completion handler closure. The problem is that this runs asynchronously, and thus didUpdateLocations may receive additional location updates in the intervening period. And often, when you first start location services, you'll get a number of updates, often with increasing accuracy (e.g. horizontalAccuracy values that are smaller and smaller). If you turn off location services before initiating asynchronous geocode request, you'll minimize this issue.

  2. You can also add add a distanceFilter in viewDidLoad, which will minimize redundant calls to the delegate method:

    locationManager.distanceFilter = 1000
    
  3. You can use your own state variable that checks to see if the reverse geocode process has been initiated. For example:

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



回答2:


I had the same problem and Rob's answer didn't do it for me.

When the location service first starts, the location is updated multiple times regardless of the distanceFilter.

You might still want the location to be updated and you don't want to lose the location accuracy(which is the whole point of updating location multiple times on start-up), so calling stopUpdatingLocation(or using a local variable) after the first geolocating call isn't the way to go either.

The most intuitive way is to wrap your geocode call in an @objc function and call the the function with a delay:

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


来源:https://stackoverflow.com/questions/34033506/swift-locationmanager-looping-through-multiple-times

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!