connorvo
connorvo

Reputation: 821

SwiftUI ObservableObject not updating when value is Published

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

Answers (3)

user20791887
user20791887

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

Rob Napier
Rob Napier

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

Asperi
Asperi

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

Related Questions