我写了一个类UserLocation(下面),它使用CoreLocation来获取用户的当前位置(字符串)&纬度和经度(也是一个字符串" lat,long"用于传递给API)。
我的代码可以工作,但是当我初始化类时,我的其余代码在继续之前不会等待init完成,所以我错过了分配与位置相关的值的机会。 39;我试图检索。
这是一个合理的方法吗(或者我应该考虑其他更多的" MVC"组织),如果是,我怎样才能让我的代码等待初始化(使用location find& amp;反向地理编码)在继续前完成。有没有办法将代码放在初始化之下的某种@escaping闭包中,这个闭包是在类初始化中指定的?我很快乐,所以感谢你的善意。
在ViewController.swift的viewDidAppear()中:
let userLocation = UserLocation() // initializes properly but code below doesn't wait.
locationsArray[0].name = userLocation.place
locationsArray[0].coordinates = userLocation.coordinates
我的UserLocation.swift类:
import Foundation
import CoreLocation
class UserLocation {
var place = ""
var coordinates = ""
let locationManager = CLLocationManager()
var currentLocation: CLLocation!
init() {
returnResults()
}
func returnResults () {
getUserLocation { placemark in
if placemark != nil {
self.place = (placemark?.name)!
self.coordinates = "\((placemark?.location?.coordinate.latitude)!),\((placemark?.location?.coordinate.longitude)!)"
} else {
print("Error retrieving placemark")
}
}
}
func getUserLocation(completion: @escaping (CLPlacemark?) -> ()) {
var placemark: CLPlacemark?
locationManager.requestWhenInUseAuthorization()
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways) {
currentLocation = locationManager.location
let geoCoder = CLGeocoder()
geoCoder.reverseGeocodeLocation(currentLocation) { (placemarks, error) -> Void in
if error != nil {
print("Error getting location: \(error)")
placemark = nil
} else {
placemark = placemarks?.first
}
completion(placemark)
}
}
}
}
extension CLPlacemark {
var cityState: String {
var result = ""
switch (self.locality, self.administrativeArea, self.country) {
case (.some, .some, .some("United States")):
result = "\(locality!), \(administrativeArea!)"
case (.some, _ , .some):
result = "\(locality!), \(country!)"
default:
result = name ?? "Location Unknown"
}
return result
}
}
答案 0 :(得分:3)
这不一定是Swift问题。您的问题是由于returnResults
以异步方式执行变量设置,因为它调用异步函数 - getUserLocation
,与reverseGeocodeLocation
异步是异步(这是CoreLocation的方式)工作 - 您不能同步获取位置,但在回调中。
您不希望等待returnResults
执行回调,因为这意味着在CoreLocation
初始化并尝试确定位置时阻止主线程。相反,您应该使用returnResults
可用于表示位置检索完成的完成块来遵循异步模式。
以上的一个例子是:
class UserLocation {
var place = ""
var coordinates = ""
let locationManager = CLLocationManager()
var currentLocation: CLLocation!
init() {
// don't call anymore from here, let the clients ask for the locations
}
// This was renamed from returnResults to a more meaningful name
// Using the Bool in the completion to signal the success/failure
// of the location retrieval
func updateLocations(withCompletion completion: @escaping (Bool) -> Void) {
getUserLocation { placemark in
if placemark != nil {
self.place = (placemark?.name)!
self.coordinates = "\((placemark?.location?.coordinate.latitude)!),\((placemark?.location?.coordinate.longitude)!)"
completion(true)
} else {
print("Error retrieving placemark")
completion(false)
}
}
}
...
然后,您可以将被调用的代码修改为:
let userLocation = UserLocation()
userLocation.updateLocations { success in
guard success else { return }
locationsArray[0].name = userLocation.place
locationsArray[0].coordinates = userLocation.coordinates
}
您不会阻止主线程,并在位置可用时执行相应的代码。