Reputation: 821
I have a view and a viewModel that should update the ListView when users are added to the user array. I can verify that users are being added, yet the ObservedObject is not updating.
I have a search bar that lets you search users and then updates user array in the ViewModel which is supposed to update the View but it doesn't.
ViewModel
class UsersViewModel: ObservableObject {
@Published var users: [User] = []
@Published var isLoading = false
var searchText: String = ""
func searchTextDidChange() {
isLoading = true
API.User.searchUser(text: searchText) { (users) in
self.isLoading = false
self.users = users
}
// confirmed that users has data now at this point
}
}
View
struct UsersView: View {
@ObservedObject var usersViewModel = UsersViewModel()
var body: some View {
VStack() {
SearchBarView(text: $usersViewModel.searchText, onSearchButtonChanged: usersViewModel.searchTextDidChange)
// Not getting called after usersViewModel.users gets data
if (usersViewModel.users.count > 0) {
Text(usersViewModel.users[0].username)
}
}
}
}
Upvotes: 6
Views: 7737
Reputation: 91
If your view is inside another view and you are not injecting the view model, consider using @StateObject
.
This will not cause the object to be renewed every time the view is re-rendered.
Upvotes: 2
Reputation: 299265
You are likely winding up with different UsersViewModel objects:
@ObservedObject var usersViewModel = UsersViewModel()
Since UsersView is a struct, this creates a new model every time the View is instantiated (which can happen very often, not just when the view appears). In iOS 14 there is @StateObject
to combine State (which preserves information between View instantiations) with ObservedObject, but in iOS 13 I recommend passing in the ObservedObject if it's not a shared instance.
Upvotes: 11
Reputation: 257493
Try to update on main queue
API.User.searchUser(text: searchText) { (users) in
DispatchQueue.main.async {
self.isLoading = false
self.users = users
}
}
Upvotes: 3