I’m confused by the MVVM architecture, especially when in consideration with having references inside of @Observable
classes. Consider the following example:
Suppose I’m implementing an app that needs location authorizations. I want to display a sheet view asking for the authorization if the user hasn’t given it. For this, I need some kind of location delegate that responds to authorization status changes. Sources ([1] [2]) generally suggest implementing something like this:
final class LocationManager: NSObject {
static let shared = LocationManager()
private let locationManager = CLLocationManager()
var isAuthorized = false
override init() {
super.init()
locationManager.delegate = self
}
}
extension LocationManager: CLLocationManagerDelegate {
func locationManagerDidChangeAuthorization(_ lm: CLLocationManager) {
// Respond to auth changes
switch locationManager.authorizationStatus {
case .authorizedAlways, .authorizedWhenInUse:
isAuthorized = true
default:
isAuthorized = false
}
}
}
And consider the simplest scenario where I am to implement a view that shows a sheet when isAuthorized
is false. My “view” and “view-model” might look something like:
struct ContentView: View {
@State var viewModel = ViewModel()
var body: some View {
SomeOtherView()
.sheet(isPresented: $viewModel.isNotAuthorized) {
Text("Please authorize location services")
.interactiveDismissDisabled()
}
}
@Observable class ViewModel {
var isNotAuthorized = !LocationManager.shared.isAuthorized
}
}
Correct me if I’m wrong, but I don’t think changes to isNotAuthorized
are properly observed. So I see a few possible solutions:
-
I mark
LocationManager
itself as@Observable
, in which case the hope would be thatisNotAuthorized
inside ofViewModel
would be trying to reference a published variable inside of another@Observable
class. I’m not sure if this would work, nor whether if it would be a good idea from a code practice perspective. -
I use
LocationManager
directly inside of my view, in which case I would be forgoing the “view-model” in the architecture. Perhaps this is fine since MVVM is just a construct, but this means thatLocationManager
would now need to manage the states of different views. i.e. I would need to have another variable namedisNotAuthorized
inside ofLocationManager
. When there’s multiple views and view states, it becomes a mess. -
I forgo any type of state management inside of
LocationManager
and push all state managements to every view’s “view-model”, I can perhaps achieve this with some sort of call back, but this seems impractical. Namely, this means for any model I implement, it cannot hold any state and must provide ways for view-models to process state changes.
Hence my confusion. It feels like I can either implement MVVM with nested observation or force myself to do unnecessarily complex state managements. Is there something simple I’m missing?