[英]How do I propertly subscribe to location updates when a View is visible?
我創建了一個實現CLLocationDelegate
和ObservableObject
的 class ,以便它可以讓視圖使用@StateObject
和@EnvironmentObject
訂閱位置更新。 這很好用,但是因為只有某些視圖需要訪問該位置,所以我想在這些視圖出現或消失時調用startUpdatingLocation
和stopUpdatingLocation
。
假設我的視圖可以訪問委托及其位置管理器,我應該將startUpdatingLocation
和stopUpdatingLocation
調用放在哪里?
我的第一個傾向是像這樣使用onAppear
和onDisappear
。
struct ViewThatNeedsLocation : View {
@EnvironmentObject var locationDelegate: MyLocationDelegate
var body: some View {
Text("")
.onAppear {
locationDelegate.manager.startUpdatingLocation()
}.onDisappear {
locationDelegate.manager.stopUpdatingLocation()
}
}
}
但這有幾個問題:
onAppear
和onDisappear
可以由於父級更改而被多次調用,即使用戶從未看到視圖明顯更改。onDisappear
調用之前調用onAppear
。這意味着我可以獲得以下事件順序
onAppear
startUpdatingLocation (good)
onAppear (again)
startUpdatingLocation (redundant)
onDisappear (?)
stopUpdatingLocation (bad)
我的猜測是ViewThatNeedsLocation
被多次創建和銷毀,而渲染的內容沒有被更改。 如果SwiftUI
提供了某種關於生命周期修飾符的順序的保證,這會很好,但事實並非如此。
這樣做的正確方法是什么? 當視圖可靠地出現和消失時,是否有一種簡單的方法來觸發設置和拆卸功能?
class LocationManager: NSObject, ObservableObject {
private let locationManager = CLLocationManager()
@Published var authorizationStatus: CLAuthorizationStatus = .notDetermined
@Published var location: CLLocation?
@Published var region: CLRegion?
override init() {
super.init()
self.locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
}
extension LocationManager: CLLocationManagerDelegate {
func requestLocation() {
locationManager.requestLocation()
}
func updateLocation() {
locationManager.startUpdatingLocation()
}
func stopUpdatingLocation() {
locationManager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
self.authorizationStatus = status
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
self.location = location
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("error getting location \(error.localizedDescription)")
}
}
在視圖結構中:
@ObservedObject var locationManager = LocationManager()
@State private var location: CLLocation?
.onReceive(locationManager.$location, perform: userLocation)
.onReceive(locationManager.$authorizationStatus, perform: { status in
switch status {
case .authorizedAlways:
locationManager.updateLocation()
case .authorizedWhenInUse:
locationManager.updateLocation()
default:
break
}
})
我只需要第一個位置,所以我在 userLocation function 的視圖中調用 locationManager.stopUpdatingLocation(),但您可以在 onDisapear 中執行此操作。 在這里你有一些演示
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.