簡體   English   中英

當視圖可見時,如何正確訂閱位置更新?

[英]How do I propertly subscribe to location updates when a View is visible?

我創建了一個實現CLLocationDelegateObservableObject的 class ,以便它可以讓視圖使用@StateObject@EnvironmentObject訂閱位置更新。 這很好用,但是因為只有某些視圖需要訪問該位置,所以我想在這些視圖出現或消失時調用startUpdatingLocationstopUpdatingLocation

假設我的視圖可以訪問委托及其位置管理器,我應該將startUpdatingLocationstopUpdatingLocation調用放在哪里?

我的第一個傾向是像這樣使用onAppearonDisappear

struct ViewThatNeedsLocation : View {
  @EnvironmentObject var locationDelegate: MyLocationDelegate

  var body: some View {
    Text("")
      .onAppear {
        locationDelegate.manager.startUpdatingLocation()
      }.onDisappear {
        locationDelegate.manager.stopUpdatingLocation()
      }
  }
}

但這有幾個問題:

  • onAppearonDisappear可以由於父級更改而被多次調用,即使用戶從未看到視圖明顯更改。
  • 不保證在后續的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM