SwiftUI - Navigate to view after retrieving data

Viewed 725

So I'm retrieving data from FireStore. I'm retrieving the data successfully. When I tap my search button the first time the data is being downloaded and the new view is pushed. As a result, I get a blank view. But when I go back, hit search again, sure enough I can see my data being presented.

How can I make sure I first have the data I'm searching for THEN navigate to the new view? I've used @State variables etc. But nothing seems to be working. I am using the MVVM approach.

My ViewModel:

class SearchPostsViewModel: ObservableObject {
    var post: [PostModel] = []
 @State var searchCompleted: Bool = false
    func searchPosts(completed: @escaping() -> Void, onError: @escaping(_ errorMessage: String) -> Void) {
            isLoading = true
        API.Post.searchHousesForSale(propertyStatus: propertyStatus, propertyType: propertyType, location: location, noOfBathrooms: noOfBathroomsValue, noOfBedrooms: noOfBedroomsValue, price: Int(price!)) { (post) in
            self.post = post
            print(self.post.count)
            self.isLoading = false
            self.searchCompleted.toggle()
        }
    

    }
    
}

The code that does work, but with the bug:

                    NavigationLink(destination: FilterSearchResults(searchViewModel: self.searchPostsViewModel)
                        .onAppear(perform: {
                            DispatchQueue.main.async {
                                self.createUserRequest()
                            }
                        })
                        )
                      {
                        Text("Search").modifier(UploadButtonModifier())
                    }
2 Answers

Try with the following modified view model

class SearchPostsViewModel: ObservableObject {
    @Published var post: [PostModel] = []         // << make both published
    @Published var searchCompleted: Bool = false

    func searchPosts(completed: @escaping() -> Void, onError: @escaping(_ errorMessage: String) -> Void) {
            isLoading = true
        API.Post.searchHousesForSale(propertyStatus: propertyStatus, propertyType: propertyType, location: location, noOfBathrooms: noOfBathroomsValue, noOfBedrooms: noOfBedroomsValue, price: Int(price!)) { (post) in
            DispatchQueue.main.async {
               self.post = post           // << update on main queue
               print(self.post.count)
               self.isLoading = false
               self.searchCompleted.toggle()
           }
        }
    }
}

You should look at the Apple documentation for @State and ObservableObject

https://developer.apple.com/documentation/combine/observableobject

https://developer.apple.com/documentation/swiftui/state

Your issue is with using an @State in a non-UI class/View.

It might help if you start with the Apple SwiftUI tutorials. So you understand the differences in with the wrappers and learn how it all connects.

https://developer.apple.com/tutorials/swiftui

Also, when you post questions make sure your code can be copied and pasted onto Xcode as-is so people can test it. You will get better feedback if other developers can see what is actually happening. As you progress it won't be as easy to see issues.

Related