显示 API 调用数据到新视图

Display API call data to new View

我的 API 调用完成后,正在尝试在视图中显示文本。当用户在 onSubmit 中提交文本字段时,我将变量保存到我的 Binding foodName,然后将其传递到新视图 (searchResultsView) 如果我将数据显示为文本,它会起作用,但是一旦我尝试传递数据并将其显示在它没有的单独视图中。

我的猜测是我在 api 调用之前加载视图(或者我可能完全不相信我的猜测)。任何反馈都会有所帮助。谢谢。

API呼叫

class FoodApiSearch: ObservableObject{
    @Published 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=***tDvDZVOy8cqG") 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()
    }
}

调用 SearchResultsView 的结构

struct testA: View {
    //Textfield
    @State var userFoodInput = ""
    @State private var didUserSearch = false
    //will store api var of foodName
    @StateObject private var foodApi = FoodApiSearch()
    //send to food results view
    @State private var  foodName = ""
    var body: some View {
            VStack{
                TextField("enter first name", text: $userFoodInput)
                    .onSubmit {
                        didUserSearch = true
                        foodApi.searchFood(userItem: userFoodInput)
                        foodName = foodApi.foodDescription
                    }
                
                FoodSearchResultsView(foodName: $foodName, userSearch: $didUserSearch)
        }
    }
}

SearchResultsView(正在调用视图)

struct FoodSearchResultsView: View {
    //calls API
    @StateObject private var foodApi = FoodApiSearch()
    @State private var searchResultsItem = ""
    @Binding var foodName: String
    //if toggled, will display, binded to search bar
    @Binding var userSearch: Bool
  
    var body: some View {
        if userSearch{
            VStack{
                Text("Best Match")
                HStack{
                    VStack(alignment: .leading){
                        Text(foodName)
                        Text("1 Cup")
                            .font(.caption)
                            .offset(y:8)
                        }
                            .foregroundColor(.black)
                    Spacer()
                    Text("72 Cals")
                }
                
                .frame(width:225, height:50)
                .padding([.leading, .trailing], 45)
                .padding([.top, .bottom], 10)
                .background(RoundedRectangle(
                    cornerRadius:20).fill(Color("LightWhite")))
                .foregroundColor(.black)
                
                Button("Add Food"){
                   userSearch = false
                }
                .padding()
            }
            .frame(maxWidth:.infinity, maxHeight: 700)
        }
    }
}

你的怀疑是对的:

当你这样做时:

foodName = foodApi.foodDescription

网络调用还没有完成。

重组您的代码。不需要 foodName 变量,因为您的 FoodApiSearch 中已经有了一个。将其传递给您的子视图并在那里访问它。一旦网络调用完成,它应该会更新您的视图并显示结果。

struct testA: View {
    //Textfield
    @State var userFoodInput = ""
    @State private var didUserSearch = false
    //will store api var of foodName
    @StateObject private var foodApi = FoodApiSearch()
    //send to food results view
    //@State private var  foodName = ""
    var body: some View {
            VStack{
                TextField("enter first name", text: $userFoodInput)
                    .onSubmit {
                        didUserSearch = true
                        foodApi.searchFood(userItem: userFoodInput)
//                        foodName = foodApi.foodDescription
                    }
                
                FoodSearchResultsView(userSearch: $didUserSearch)
                    .environmentObject(foodApi)
        }
    }
}

struct FoodSearchResultsView: View {
    //calls API
    @EnvironmentObject private var foodApi: FoodApiSearch
    @State private var searchResultsItem = ""
//    @Binding var foodName: String
    //if toggled, will display, binded to search bar
    @Binding var userSearch: Bool
  
    var body: some View {
        if userSearch{
            VStack{
                Text("Best Match")
                HStack{
                    VStack(alignment: .leading){
                        Text(foodApi.foodDescription)
                        Text("1 Cup")
                            .font(.caption)
                            .offset(y:8)
                        }
                            .foregroundColor(.black)
                    Spacer()
                    Text("72 Cals")
                }
                
                .frame(width:225, height:50)
                .padding([.leading, .trailing], 45)
                .padding([.top, .bottom], 10)
                .background(RoundedRectangle(
                    cornerRadius:20).fill(Color("LightWhite")))
                .foregroundColor(.black)
                
                Button("Add Food"){
                   userSearch = false
                }
                .padding()
            }
            .frame(maxWidth:.infinity, maxHeight: 700)
        }
    }
}