qsaluan
qsaluan

Reputation: 59

How to copy user location only once from location manager?

I have a function inside a location manager class that obtains the current location coordinates of the user. It updates too frequently for my usage in another View. I am trying to come up with a way to obtain the location less frequently or a limited number of times but have not been able to come up with anything. My guess is that it will require timestamping or such approach which I am not familiar with. Any help is greatly appreciated.

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    guard let location = locations.last else { return }

    // self.location = location does the copying here too frequently
    self.location = location
    
    self.reverseGeocode()
}

SOLUTION:

After much trial and error the solution ended up being the difference between the Observable Object property wrapper and the State Object property wrapper. My issue was that the Observable Object property wrapper allowed the variable I used in my view to change continuously which was not what I wanted in my specific situation. Once I changed it to a State Object, it did exactly what I wanted it to do which was update once when the location changed.

For those interested here is a good blog post outlining these key differences: https://www.donnywals.com/whats-the-difference-between-stateobject-and-observedobject/.

Upvotes: 1

Views: 358

Answers (2)

Fabian
Fabian

Reputation: 5348

You can try Publishers. An untested example using throttle follows.

The throttle docs:

Publishes either the most-recent or first element published by the upstream publisher in the specified time interval.

// Setup:
let locationPublisher = PassthroughSubject<CGFloat, Never>()

// Send updates.
locationPublisher.send(value)

// Update only every x seconds.
struct MyView {
    @State var location: CGFloat? = nil
    var body: some View {
        Text("Value: \(location)")
        .onReceive(
            locationPublisher
            .throttle(for: 1.0, scheduler: RunLoop.main, latest: true) {
        ){
            self.location = $0
        }
    }
}

To get only the first update there is also a way with .first()

Upvotes: 1

matt
matt

Reputation: 534925

If the goal is to learn our location once, don't begin updating locations at all. Instead, just call requestLocation. This will give you a single update (after a possible delay).

Upvotes: 4

Related Questions