我是iOS开发人员的新手,很抱歉,这是一个明显的问题。但是我不知道如何更新SwiftUI列表中的数据。我正在从API提取数据,并使用@ObservedObject将其传递给ContentView。当我启动应用程序时,它可以正常工作,但是在我更改了API请求(通过在SearchBar中键入关键字)并再次获取它之后,即使数据已更改,它似乎也没有更新List。< / p>
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?
}
答案 0 :(得分:1)
我做了一些小的修改,并使代码在Xcode-playgrounds中工作。方法如下:
型号:
struct News: Codable { var articles: [Post] }
struct Post: Identifiable, Codable { var title: String; var id: String { title } }
ContentView:
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()
}
}
}
NetworkManager:
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()
}
}
}