显示 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)
}
}
}
我的 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)
}
}
}