【发布时间】:2021-03-08 09:59:26
【问题描述】:
我正在使用 SwiftUI 和 CLLocationManager。这是我的 LocationModel:
class LocationViewModel: NSObject, ObservableObject{
@Published var userLatitude: Double = 0
@Published var userLongitude: Double = 0
@Published var userTown: String = ""
var objectWillChange = ObservableObjectPublisher()
private let locationManager = CLLocationManager()
override init() {
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
}
extension LocationViewModel: CLLocationManagerDelegate {
struct ReversedGeoLocation {
let name: String // eg. Apple Inc.
let streetName: String // eg. Infinite Loop
let streetNumber: String // eg. 1
let city: String // eg. Cupertino
let state: String // eg. CA
let zipCode: String // eg. 95014
let country: String // eg. United States
let isoCountryCode: String // eg. US
var formattedAddress: String {
return """
\(name),
\(streetNumber) \(streetName),
\(city), \(state) \(zipCode)
\(country)
"""
}
// Handle optionals as needed
init(with placemark: CLPlacemark) {
self.name = placemark.name ?? ""
self.streetName = placemark.thoroughfare ?? ""
self.streetNumber = placemark.subThoroughfare ?? ""
self.city = placemark.locality ?? ""
self.state = placemark.administrativeArea ?? ""
self.zipCode = placemark.postalCode ?? ""
self.country = placemark.country ?? ""
self.isoCountryCode = placemark.isoCountryCode ?? ""
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
userLatitude = location.coordinate.latitude
userLongitude = location.coordinate.longitude
userTown = getTown(lat: CLLocationDegrees.init(userLatitude), long: CLLocationDegrees.init(userLongitude))
print(location)
}
func getTown(lat: CLLocationDegrees, long: CLLocationDegrees) -> String
{
var town = ""
let location = CLLocation.init(latitude: lat, longitude: long)
CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in
guard let placemark = placemarks?.first else {
let errorString = error?.localizedDescription ?? "Unexpected Error"
print("Unable to reverse geocode the given location. Error: \(errorString)")
return
}
let reversedGeoLocation = ReversedGeoLocation(with: placemark)
print(reversedGeoLocation.city)
town = reversedGeoLocation.city
self.objectWillChange.send()
}
return town
}
}
现在我想显示当前坐标和城市,但只是没有显示城市,似乎变量没有正确更新。怎么做?这是我的看法:
@ObservedObject var locationViewModel = LocationViewModel()
var latitude: Double { return(locationViewModel.userLatitude ) }
var longitude: Double { return(locationViewModel.userLongitude ) }
var town: String { return(locationViewModel.userTown) }
var body: some View {
VStack {
Text("Town: \(town)")
Text("Latitude: \(latitude)")
Text("Longitude: \(longitude)")
}
}
我不完全明白如何在位置更改或 getTown 函数完成关闭时将更新后的变量传递到视图中。
【问题讨论】:
-
如果您使用
self.objectWillChange.send(),您希望视图仅在特定更改时刷新,而不是在每次更新时刷新。使用当前模型,您每次都在进行更新,因为属性也标记为@published,我认为这不是必需的,另一件事是您不需要显式定义此依赖关系var objectWillChange = ObservableObjectPublisher()。您可以在 getTown 函数中直接使用self.objectWillChange.send()。实际问题是经纬度更新? -
这一切都很好,我可以在 getTown() (在位置管理器内部)中看到正在打印的城镇,但是当我尝试在文本标签的主视图中打印它时,它就出现了为空。你知道那里发生了什么吗?
-
您的
getTown函数将始终返回空字符串,因为您在该函数内部有async调用,在点击CLGeocoder().reverseGeocodeLocation(location)行后调用将直接返回调用,并返回空字符串。所以你的 userTown 总是“”。您可以直接在闭包块内使用userTown变量,而不是Town变量。
标签: ios swift swiftui core-location cllocationmanager