swift - 如何在 SwiftUI 列表中重新加载数据?

标签 swift api swiftui

我是 iOS 开发的新手,如果这是一个明显的问题,我很抱歉。但我不知道如何更新 SwiftUI 列表中的数据。我正在从 API 获取数据并使用 @ObservedObject 将其传递给 ContentView。当我启动我的应用程序时它工作正常,但是在我更改我的 API 请求(通过在 SearchBar 中输入关键字)并再次获取它之后,它似乎没有更新列表,即使数据已更改。
ContentView.swift

struct ContentView: View {

@ObservedObject var networkManager = NetworkManager()

@State var searchText: String = ""

var body: some View {
    NavigationView{
        VStack {
            SearchBar(text: $searchText, placeholder: "Enter a keyword")
            List(networkManager.posts) { post in
                NavigationLink(destination: DetailView(url: post.url)) {
                    HStack {
                        Text(post.title)
                    }
                }
                
            }.gesture(DragGesture().onChanged { _ in UIApplication.shared.endEditing() })
            
        }.navigationBarTitle("News")
        
    }
    .onAppear {
        self.networkManager.fetchData(self.searchText)
    }
    
}
}
NetworkManager.swift
class NetworkManager: ObservableObject {



@Published var posts = [Post]()

func fetchData(_ keyword: String?){
    var urlString = "https://newsapi.org/v2/top-headlines?country=us&apiKey=5dcef32f4c69413e8fe128cc5c7ba4cf"
    if keyword != nil {
        urlString = "https://newsapi.org/v2/top-headlines?country=us&apiKey=5dcef32f4c69413e8fe128cc5c7ba4cf&q=\(keyword!)"
    }
    print(urlString)
    if let url = URL(string: urlString){
        let session = URLSession(configuration: .default)
        let task = session.dataTask(with: url) { (data, response, error) in
            if error == nil{
                let decoder = JSONDecoder()
                if let safeData = data{
                    do{
                        let results = try decoder.decode(News.self, from: safeData)
                        DispatchQueue.main.async {
                            self.posts = results.articles
                            print(self.posts)
                        }
                    } catch{
                        print(error)
                    }
                }
            }
        }
        task.resume()
    }
    
}

}
SearchBar.swift (我再次在 searchBarSearchButtonClicked 中获取数据)
struct SearchBar: UIViewRepresentable {
    
    
    @Binding var text: String
    var placeholder: String
    
    class Coordinator: NSObject, UISearchBarDelegate {
       
        @ObservedObject var networkManager = NetworkManager()
        
        @Binding var text: String
        
        init(text: Binding<String>) {
            _text = text
        }
        
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            text = searchText
        }
        
        func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
            print(text)
            DispatchQueue.main.async {
                self.networkManager.fetchData(self.text)
            }
            
            UIApplication.shared.endEditing()
            
        }
    }
    
    func makeCoordinator() -> SearchBar.Coordinator {
        return Coordinator(text: $text)
    }
    
    func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        searchBar.placeholder = placeholder
        searchBar.searchBarStyle = .minimal
        searchBar.autocapitalizationType = .none
        return searchBar
    }
    
    func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext<SearchBar>) {
        uiView.text = text
    }
    
}

extension UIApplication {
    func endEditing() {
        sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}
News.swift
struct News: Decodable {
    let articles: [Post]
}

struct Post: Decodable, Identifiable {
    var id: String{
        return url!
    }
    let title: String
    let url: String?
}

最佳答案

我做了一些小的修改并使代码在 Xcode-playgrounds 中工作。就是这样:
模型:

struct News: Codable { var articles: [Post] }
struct Post: Identifiable, Codable { var title: String; var id: String { title } }
内容 View :
struct ContentView: View {

    @ObservedObject var networkManager = NetworkManager()

    var body: some View {
        NavigationView {
            VStack {
                TextField("Enter a keyword", text: $networkManager.searchText)
                List(networkManager.posts) { post in
                    NavigationLink(destination: EmptyView()) {
                        HStack {
                            Text(post.title)
                        }
                    }
                }
            }.navigationBarTitle("News")
        }
        .onAppear {
            self.networkManager.fetchData()
        }

    }
}
网络管理员:
class NetworkManager: ObservableObject {

    @Published var searchText: String = "" {
        didSet {
            fetchData()
        }
    }
    @Published var posts = [Post]()

    func fetchData() {
        let urlString = "https://newsapi.org/v2/top-headlines?country=us&apiKey=5dcef32f4c69413e8fe128cc5c7ba4cf&q=\(searchText)"
        if let url = URL(string: urlString){
            let session = URLSession(configuration: .default)
            let task = session.dataTask(with: url) { (data, response, error) in
                if error == nil{
                    let decoder = JSONDecoder()
                    if let safeData = data{
                        do{
                            let results = try decoder.decode(News.self, from: safeData)
                            DispatchQueue.main.async {
                                self.posts = results.articles
                                print(self.posts)
                            }
                        } catch{
                            print(error)
                        }
                    }
                }
            }
            task.resume()
        }
    }
}

关于swift - 如何在 SwiftUI 列表中重新加载数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62640643/

相关文章:

swift - 使用已发布的结果为 ObservableObject ViewModel 编写单元测试

swiftui - 在没有导航链接的情况下更改 View SwiftUI

ios - 是什么导致 SIGILL 在 iOS 上带有 ILL_ILLTRP 代码?

ios - 当 Apple 从设置中删除 Twitter 时,如何在 Xcode 9 Simulator 中访问它?

ios - Segue 不执行 iOS8

api - 每 X 分钟向我发送一次 HTTP GET 请求

javascript - Uncaught ReferenceError : datapoint is not defined. 从 api 调用 json 数据时

api - 通过 API POSTMAN 在 Stripe 中创建卡片 token

ios - 为什么我的 TableView 只显示每个单元格中加载的最后一张图像? ( swift )

ios - 在 SwiftUI 中调出 Google 登录屏幕