Home > other >  Trying to display API results to View
Trying to display API results to View

Time:04-07

Attempting to display text to a view once my API call is complete. I figured I would just save the API result I wanted (foodDescription) to a variable once the data loaded, then display the variable in the view.

My guess is I'm loading the view before the api call (or I could be completely off with my guess which I probably am). I also feel I am using the DispatchQueue incorrectly and would love to feedback as well. Thank you in advance.

API CALL

 class FoodApiSearch{
        var foodDescription = ""
        //will search for user Input
        func searchFood(userItem: String){
           //calls api search
            guard let url = URL(string: "https://api.nal.usda.gov/fdc/v1/foods/search?query=\(userItem)&dataType=&pageSize=1&pageNumber=1&api_key=*****") else {return}
            
            URLSession.shared.dataTask(with: url) { (data, _,_) in
                let searchResults = try! JSONDecoder().decode(APISearchResults.self, from: data!)
                
                DispatchQueue.main.async {
                    for item in searchResults.foods{
                            self.foodDescription = item.foodDescription ?? "food not valid"
                            print(self.foodDescription)
                        }
                    }
            }
            .resume()
        }
    }

STRUCT

  struct testA: View {
        //Textfield
        @State var userFoodInput = ""
        //will store api var of foodName
        @State var foodName = ""
        var body: some View {
                VStack{
                    TextField("enter first name", text: $userFoodInput)
                    Button("click me"){
                        //action
                
                        FoodApiSearch().searchFood(userItem: userFoodInput)
                       foodName =  FoodApiSearch().foodDescription
                    }
                    Text("You searched for "   foodName)
            }
        }
    }

CodePudding user response:

Because searchFood is asynchronous, you can't just assign foodName = FoodApiSearch().foodDescription on a subsequent line and expect it to return the right result. There's also another issue: you're creating two different instances of FoodApiSearch (each time you type FoodApiSearch() it's a new instance).

You're probably looking to make FoodApiSearch an ObservableObject with a @Published property. That would look like this:

class FoodApiSearch : ObservableObject {
   @Published  var foodDescription = ""

   func searchFood(userItem: String) {

Then, you store a single instance of it using @StateObject in your View and if you want to display the result, use the @Published variable -- don't try to assign it to a local @State:

struct TestA: View {
        @State private var userFoodInput = ""
        @StateObject private var foodApi = FoodApiSearch()

        var body: some View {
                VStack{
                    TextField("enter first name", text: $userFoodInput)
                    Button("click me") {
                        foodApi.searchFood(userItem: userFoodInput)
                    }
                    if !foodApi.foodDescription.isEmpty {
                        Text(foodApi.foodDescription)
                    }
            }
        }
    }
  • Related