SWIFT - LocationManager 循环多次?
SWIFT - LocationManager looping through multiple times?
我有一个 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) 中,它将在我的控制台中打印 3 次。这正常吗?
更新以显示 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
}
我首先建议几件事:
在执行 reverseGeocodeLocation
之前调用 stopUpdatingLocation
。
您正在 reverseGeocodeLocation
完成处理程序闭包中调用 stopUpdatingLocation
。问题在于它是异步运行的,因此 didUpdateLocations
可能会在此期间收到额外的位置更新。通常,当您第一次启动位置服务时,您会获得许多更新,而且准确性通常会越来越高(例如,horizontalAccuracy
值越来越小)。如果您在启动异步地理编码请求之前关闭位置服务,您将最大限度地减少此问题。
你也可以在viewDidLoad
中添加一个distanceFilter
,这将最大限度地减少对委托方法的冗余调用:
locationManager.distanceFilter = 1000
您可以使用自己的状态变量来检查反向地理编码过程是否已启动。例如:
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 的回答对我没有帮助。
当定位服务第一次启动时,无论距离过滤器如何,都会多次更新位置。
您可能仍希望更新位置并且不想丢失位置准确性(这是在启动时多次更新位置的全部意义),因此调用 stopUpdatingLocation(或使用本地变量)在第一次地理定位调用之后也不是要走的路。
最直观的方法是将地理编码调用包装在@objc 函数中并延迟调用该函数:
NSObject.cancelPreviousPerformRequests(withTarget: self)
perform(#selector(myGeocodeFunction(_:)), with: location, afterDelay: 0.5)
我有一个 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) 中,它将在我的控制台中打印 3 次。这正常吗?
更新以显示 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
}
我首先建议几件事:
在执行
reverseGeocodeLocation
之前调用stopUpdatingLocation
。您正在
reverseGeocodeLocation
完成处理程序闭包中调用stopUpdatingLocation
。问题在于它是异步运行的,因此didUpdateLocations
可能会在此期间收到额外的位置更新。通常,当您第一次启动位置服务时,您会获得许多更新,而且准确性通常会越来越高(例如,horizontalAccuracy
值越来越小)。如果您在启动异步地理编码请求之前关闭位置服务,您将最大限度地减少此问题。你也可以在
viewDidLoad
中添加一个distanceFilter
,这将最大限度地减少对委托方法的冗余调用:locationManager.distanceFilter = 1000
您可以使用自己的状态变量来检查反向地理编码过程是否已启动。例如:
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 的回答对我没有帮助。
当定位服务第一次启动时,无论距离过滤器如何,都会多次更新位置。
您可能仍希望更新位置并且不想丢失位置准确性(这是在启动时多次更新位置的全部意义),因此调用 stopUpdatingLocation(或使用本地变量)在第一次地理定位调用之后也不是要走的路。
最直观的方法是将地理编码调用包装在@objc 函数中并延迟调用该函数:
NSObject.cancelPreviousPerformRequests(withTarget: self)
perform(#selector(myGeocodeFunction(_:)), with: location, afterDelay: 0.5)