繁体   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