Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Passing Data between Delegate and ViewModel ObservableObjects

I have an app built using SwiftUI that works with user location. Using online tutorials, I have come up with a class LocationManager that handles the request using the delegate method and has an attribute @Published that sets the location as soon as it receives it.

I also have a ViewModel that has a function getData(location: CLLocation) that will properly update my view after an async call to a different API.

My question is, what is the best way to connect the LocationManager with the ViewModel, so that as soon as the LocationManager gets the location using the delegate it automatically calls the getData() function with that value?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I’ve tried to come up with a few solutions on my own, such as passing a closure to the LocationManager to call viewModel.getData() when the delegate is updated, but I got an issue with the "closure capturing a mutating self parameter". Any help would be greatly appreciated!!

Here is the code in question:

final class LocationManager: NSObject, ObservableObject {
    @Published var location: CLLocation?
    
    private let locationManager = CLLocationManager()
    
  
    override init() {
        super.init()
    
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
        locationManager.delegate = self
    }
}

extension LocationManager: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else {
            return
        }
        DispatchQueue.main.async {
            self.location = location
        }
    }
}

class ViewModel: ObservableObject {
    @Published dataArray = [Model]()

    func getData(location: CLLocation) {
         // async api call
         // update dataArray for view in completion handler
    }
}

struct ShowData: View {
     // initialize LocationManager
     @StateObject var locationManager = LocationManager()

     // initialize ViewModel
     @StateObject var viewModel = ViewModel()

     var body: some View {
          // show dataArray
     }
}

>Solution :

You can own the LocationManager in your view model:

class ViewModel: ObservableObject {
    @Published dataArray = [Model]()

    var lm = LocationManager()
}

Then, you could architect the LocationManager to take a separate delegate (which could be the view model), or, you could use Combine to listen for changes on the @Published property on the LocationManager:

cancellable = lm.$location.sink { ... }
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading