I have an iOS app with the following views:
struct LoggedInUserView: View{
@ObservedObject var viewModel: LoggedInUserViewModel
@StateObject var sharedPortionViewModel: SharedPortionViewModel(userName: "")
var body: some View{
//Some specific-to-LoggedInUser UI elements
SharedPortionUserView(sharedPortionViewModel: sharedPortionViewModel)
}
}
struct OtherUserView: View{
@ObservedObject var viewModel: OtherUserViewModel()
@StateObject var sharedPortionViewModel: SharedPortionViewModel(userName: "")
var body: some View{
//Some specific-to-OtherUser UI elements
SharedPortionUserView(sharedPortionViewModel: sharedPortionViewModel)
}
}
SharedPortionViewModel
runs the same functions to load data in both cases, but it grabs the specified user's info, depending on which view is being viewed. 100% of the time LoggedInUserView
is viewed, the logged-in-user's userName will be passed. This is stored in Keychain
.
All I am trying to do is pass the relevant user's userName to the creation of the StateObject in both cases, but I am finding this surprisingly complex to do. A variety of approaches I have seen involve custom initializers in the view, which I'd like to avoid. I also considered something like:
var passedUserName: String //tried a variety of different property wrappers
@StateObject var sharedPortionViewModel: SharedPortionViewModel(userName: passedUserName)
Such that the parent view can pass the userName in question when loading this view, but I think there are issues with passedUserName not being set at initialization to be ready to pass to sharedPortionViewModel
.
I also considered modifying the above approach by:
@State private var sharedProfileViewModel: SharedUserProfilePageViewModel?
And then initializing it via
.onAppear {
if sharedProfileViewModel == nil {
sharedProfileViewModel = SharedUserProfilePageViewModel(userName: userName)
}
}
But this just feels weird.
I could create the viewModel before initializing the navigation from the parent view, and then pass this as the already-created-viewmodel, but this feels clunky.
Am I missing something? Why is this so involved? Are these really the only ways to achieve this? Did I cover the best approach above and improperly dismissed it?
You may implicitly initialize @StateObject
like this:
struct OtherUserView: View {
@StateObject private var sharedPortionViewModel: SharedPortionViewModel
init(passedUserName: String) {
self._sharedPortionViewModel = .init(wrappedValue: .init(userName: passedUserName))
}
}