Handle Swiftui and Corelocation with Mvvm-Pattern

Handle SwiftUI and CoreLocation with MVVM-Pattern

SwiftUI 2

Use instead StateObject in this case

struct LocationView: View {

@StateObject var locationManager: LocationManager = LocationManager()
...

SwiftUI 1

Actually LocationViewModel is redundant here. As your LocationManager is a ObservableObject you can use it directly in your view, as below:

struct LocationView: View {

@ObservedObject var locationManager: LocationManager = LocationManager()

var body: some View {
VStack(alignment: .leading) {
Text("Latitude: \(locationManager.location.coordinate.latitude.description)")
Text("Longitude: \(locationManager.location.coordinate.longitude.description)")
}
}
}

Pure MVVM with SwiftUI & CoreLocation

I would use a Service-Oriented architecture approach. You can have your LocationServiceProtocol, implemented by a LocationService class, that you can inject in the view model. This class has the responsibility to instantiate your Location model and has the CLLocationManager property. In this way you can handle the interaction between the high and lower level implementations.

Mapping a single response object with SwiftUI and MVVM pattern

Seems your UserProfileService().getProfile already return UserProfile type so you maybe need to

UserProfileService().getProfile { profile in
if let profile = profile {
self.profile = profile
}
}

and

@Published var profile : UserProfile?

SwiftUI problem with displaying values from array using MVVM pattern

Conform your model to Hashable and use .self to identify it:

struct JSONModel: Codable, Hashable{
var name: String
var value: String
}



ForEach(viewModel.resultArray, id:\.self){ item in
Text(item.name)
}

Swift, fetching data in viewmodel and passing it to view

Your init() is trying to run asynchronously and it's updating a @Published property. Even if you manage to avoid compile errors, you cannot update a property that will change the state of your views (@Published) unless you are on the main thread.

What I propose:

    @Published var weather = Response()     // Initialise this property in some way, the dummy values will be used by the app until you complete fetching the data

init(weather: Response) { // Remove async
Task { // Here, you enter in an async environment
let data = await fetchData() // Read the data and pass it to a constant
DispatchQueue.main.async { // Get on the main thread
self.weather = data // Here, change the state of you app
}
}
}

I hope this works, but it would be better if after "But I stuck with compile errors..." you showed what kind of errors you find. I tried to use my best guess with the solution above.

Using startUpdatingLocation() and stopUpdatingLocation() to activate/deactivate location updates in specific Views

Solution:

My mistake was trying to call locationViewModel.locationManager.startUpdatingLocation() method before the declaration of the views's body.

        .navigationTitle("Simulation")
.navigationBarTitleDisplayMode(.inline)
.onAppear(perform: {locationViewModel.locationManager.startUpdatingLocation()})
.onDisappear(perform: {locationViewModel.locationManager.stopUpdatingLocation()})

SwiftUI get values of another ViewModel in a ViewModel

Here is possible approach

class FilterViewModel: ObservableObject, LoadProtocol {
@Published var placemarkViewModel = PlacemarkViewModel()

private var cancellable: AnyCancellable? = nil
init() {
cancellable = placemarkViewModel.$placemark
.sink { placemark in
// handle updated placemark here
}
}
}

How do I write a core location with MVVM architecture and perform unit testing?

You could create a LocationService protocol that defines all methods (for instance fetchCurrentPosition).
Then create a concrete class conforming to that protocol, that implements apple CoreLocation services; this class will be used by the view model for example, and it will be injected in the initializer. Think something like:

class MyViewModel {

let locationService: LocationService

init(locationService: LocationService = LocationServiceImpl()) {
self.locationService = locationService
}

}

LocationServiceImpl is the class conforming to LocationService that actually uses apple CoreLocation; in this way, you can later mock every function of your location service by creating for example LocationServiceMock class that conforms to LocationService; in your unit tests, you'll create a view model with the mocked service.



Related Topics



Leave a reply



Submit