微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用来自 TextField 的值执行 API 调用并在 SwiftUI 中显示结果

如何解决使用来自 TextField 的值执行 API 调用并在 SwiftUI 中显示结果

希望使用文本字段中的值执行 API 调用并将结果显示在列表中。无法使用文本字段中的 $name 值到 url 中,然后进行 API 调用

到目前为止我的代码

WebService.swift

import Foundation

public class UserFetcher: ObservableObject {

    @Published var shoes: [Shoe] = []
    @Published private var name: String = ""
    
    init(){
        load()
    }
    
    func load() {
       // let url = URL(string: "https://api.thesneakerdatabase.com/v1/sneakers?limit=10&name=wolf%20in%20sheeps%20clothing")! // the format the API requires
        let url = URL(string: "https://api.thesneakerdatabase.com/v1/sneakers?limit=10&name=" + name)!
    
        URLSession.shared.dataTask(with: url) {(data,response,error) in
            do {
                if let d = data {
                    let decodedLists = try JSONDecoder().decode(APIResponse.self,from: d)
                    dispatchQueue.main.async {
                      //  self.users = decodedLists
                        self.shoes = decodedLists.shoeResults
                    }
                }else {
                    print("No Data")
                }
            } catch {
                print ("Error")
            }
            
        }.resume()
       
    }
}

ContentView.swift

import Foundation
import SwiftUI
import Combine
import SDWebImage
import SDWebImageSwiftUI
 

    struct ContentView: View {
        @Observedobject var fetcher = UserFetcher()
        @State private var name: String = ""
        
        var body: some View {
            NavigationView  {
            vstack {
                vstack(alignment: .leading) {
                           TextField("Search",text: $name)
                       }
                List(fetcher.shoes) { Shoe in
                   
                    vstack (alignment: .leading) {
                        Text(Shoe.name)
                        Text(Shoe.shoe)
                            .font(.system(size: 11))
                            .foregroundColor(Color.gray)
                        Text(Shoe.brand)
                            .font(.system(size: 11))
                            .foregroundColor(Color.gray)
                        Text(Shoe.styleId)
                            .font(.system(size: 11))
                            .foregroundColor(Color.gray)
                        Text(".\(Shoe.year)")
                            .font(.system(size: 11))
                            .foregroundColor(Color.gray)
                        WebImage(url: URL(string: "\(Shoe.media.thumbUrl)"))
                            .resizable()
                            .aspectRatio(contentMode: .fill)
                    }
                      
                }
         
            }
             .navigationBarTitle(Text("Search"))
        }
        
    }

我确定它有一些很明显的东西,但过去两个小时一直盯着它看,似乎无法工作。任何方向将不胜感激谢谢

解决方法

尝试以下操作:

public class UserFetcher: ObservableObject {

    @Published var shoes: [Shoe] = []
    
    init(){
        //load() <- remove this
    }
    
    func load(_ name: String) { //<-- add parameter
        ....
    }
struct ContentView: View {
    @ObservedObject var fetcher = UserFetcher()
    @State private var name: String = ""
        
    var body: some View {
        NavigationView  {
            VStack {
                VStack(alignment: .leading) {
                    TextField("Search",text: $name)
                }
                List(fetcher.shoes) { Shoe in
                ...
                }
            }.onAppear(fetcher.load(name)) //<--- begin to load
        }
    }

,

如果您想要在 TextField 中输入并查看结果更新的正常行为,您可能需要这样的内容(请参阅有关更改内容的内联注释):

import SwiftUI
import Combine

public class UserFetcher: ObservableObject {
    
    @Published var shoes: [Shoe] = []
    @Published var name: String = "" // Not private any more
    
    private var cancellable : AnyCancellable?
    
    init() {
        cancellable = $name
            .debounce(for: .seconds(1),scheduler: RunLoop.main) //only run once the text has been static for 1 second
            .sink { (newSearch) in
                self.load(searchTerm: newSearch)
            }
    }
    
    func load(searchTerm: String) { //take the search term as a parameter
        guard !searchTerm.isEmpty,let url = URL(string: "https://api.thesneakerdatabase.com/v1/sneakers?limit=10&name=\(searchTerm)") else {
            return //don't search if the term is empty or the URL is invalid
        }
        
        URLSession.shared.dataTask(with: url) {(data,response,error) in
            do {
                if let d = data {
                    let decodedLists = try JSONDecoder().decode(APIResponse.self,from: d)
                    DispatchQueue.main.async {
                        self.shoes = decodedLists.shoeResults
                    }
                }else {
                    print("No Data")
                }
            } catch {
                print ("Error: \(error)") //print your error here
            }
            
        }.resume()
        
    }
}



struct ContentView: View {
    @ObservedObject var fetcher = UserFetcher()
    
    var body: some View {
        NavigationView  {
            VStack {
                VStack(alignment: .leading) {
                    TextField("Search",text: $fetcher.name) //using the name property from fetcher now
                }
                List(fetcher.shoes) { shoe in //don't use capital letters for variable names -- not idiomatically correct Swift and it can get confused with your `Shoe` type
                    VStack (alignment: .leading) {
                        Text(shoe.name)
                        Text(shoe.shoe)
                            .font(.system(size: 11))
                            .foregroundColor(Color.gray)
                        Text(shoe.brand)
                            .font(.system(size: 11))
                            .foregroundColor(Color.gray)
                        Text(shoe.styleId)
                            .font(.system(size: 11))
                            .foregroundColor(Color.gray)
                        Text(".\(shoe.year)")
                            .font(.system(size: 11))
                            .foregroundColor(Color.gray)
                    }
                    
                }
                
            }
            .navigationBarTitle(Text("Search"))
        }
    }
}

我还注意到,在测试时,您使用 Shoe 结构从您的 API 中获取错误,该结构来自您之前提出的问题 -- 确保 retailPriceInt? 而不是 { {1}} 因为有时 API 不会返回该字段的值。

我还要指出,您可以通过将 Int 问题转化为可以使用 load 链接到 Combine 调用中的内容,从而使这更加巧妙,但这值得其他研究或一个不同的问题(此处超出范围)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。