最小化使用 LocationManager 时对我的服务器发出的 HTTP 请求

Minimize HTTP requests made to my server when using LocationManager

在下面的代码中,我使用 LocationManager 获取用户的当前邮政编码,然后向我自己的服务器发出 HTTP 请求,以根据用户的邮政编码获取一些数据。我的问题是我下面的代码每次调用 locationManager 时都会发出 HTTP 请求,通常每次调用三次。理想情况下,我只想在找到最后一个地标后发出 HTTP 请求。

如何最大限度地减少对我自己的服务器发出的 HTTP 请求?

override func viewDidLoad() {
    super.viewDidLoad()
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestWhenInUseAuthorization()
    locationManager.startUpdatingLocation()
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)-> Void in
        if error != nil {
            //AlertView to show the ERROR message
        }
        if placemarks!.count > 0 {
            let placemark = placemarks![0]
            var zipCode = placemark.postalCode ?? ""
            makeHTTPRequest(zipCode) // this is called 3 times
            self.locationManager.stopUpdatingLocation()

        }else{
            print("No placemarks found.")
        }
    })
}

您的代码的问题在于,在您执行 self.locationManager.stopUpdatingLocation() 时,可能有多个对 locationManager(_:didUpdateLocations:) 的调用堆积起来。要解决这个问题:

  • 定义一个全局变量var didFindZipCode: Bool = false
  • 在检查地标数量的 if 块的开头添加 guard didFindZipCode == false else { return }
  • 在 guard 语句之后设置 didFindZipCode = true

只要记得将 didFindZipCode 设置为 false,每当您想再次开始更新位置时。

问题是您的 CLGeocoder 方法 returns 是异步的,到它 returns 一个值时,您的位置管理器已经触发了多次。因此,只需在位置管理器第一次调用后停止更新位置,然后进行异步工作。

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

    guard let location = locations.last else {
        return
    }

    // handle async work
    CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in

        if let error = error {
            // alert with error
        } else if let placemarks = placemarks,
            placemarks.count > 0 {
            let placemark = placemarks[0]
            var zipCode = placemark.postalCode ?? ""
            makeHTTPRequest(zipCode)
        } else {
            print("No placemarks found.")
        }

    })

    locationManager.stopUpdatingLocation() // stop updating

}

顺便说一句,链接 if-else 语句也是一种很好的做法。如果您以 if 开头,您几乎应该总是在其后跟一个 else,而不是在其后跟一个新的 if 块。