问题描述
我正在尝试构建一个从 newsapi.org API 数据源返回新闻项目列表的基本应用程序。我将 viewmodel 设置为从 API 获取新闻并将数据转换为模型。然后,我将我的模型设置为围绕 api 响应中的特定项目进行构建(请参阅下面 viewmodel 中 API 的 URL)。最后,我设置了我的 ContentView 以在列表中返回新闻项目。该应用程序构建良好,但新闻项(来源名称、文章标题)未填充在屏幕上,并且在控制台中我收到打印的“失败”消息。我的模型设置不正确吗?文章应该是文章的数组(例如[文章])吗?知道如何设置模型(或视图模型)以在屏幕上填充新闻项目吗?感谢您的反馈。
内容视图
import SwiftUI
struct ContentView: View {
@Observedobject var viewmodel = Newsviewmodel()
var body: some View {
NavigationView {
vstack {
List(viewmodel.articles,id: \.articles.source.id) { news in
vstack(alignment: .leading) {
Text(news.articles.source.name)
Text(news.articles.title)
Text(news.articles.description)
}
}
}
.navigationTitle("News List")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
模型
import Foundation
struct APIResponse: Codable {
let articles: Article
}
struct Article: Codable {
let source: Source
let title: String
let description: String
}
struct Source: Codable,Identifiable {
let id: String
let name: String
}
视图模型
import Foundation
class Newsviewmodel: ObservableObject {
@Published var articles = [APIResponse]()
init() {
fetchNews()
}
func fetchNews() {
guard let url = URL(string: "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=4b6cfa9b54c74b4db7d7d8a2120718d3") else {
return
}
let task = URLSession.shared.dataTask(with: url) { data,_,error in
guard let data = data,error == nil else {
return
}
do {
let model = try JSONDecoder().decode([APIResponse].self,from: data)
//update properties on the main thread
dispatchQueue.main.async {
self.articles = model
}
}
catch {
print("Failed")
}
}
task.resume()
}
}
解决方法
总是打印错误,以防您不确定为什么失败:
print("\(error)") // Instead of print("failed")
如果任何值中包含 null,则将其设为可选:
struct APIResponse: Codable {
let articles: [Article]
}
struct Article: Codable {
let source: Source
let title: String
let description: String?
}
struct Source: Codable,Identifiable {
let id: String?
let name: String?
}
更新视图:
struct ContentView: View {
@ObservedObject var viewModel = NewsViewModel()
var body: some View {
NavigationView {
List(viewModel.articles,id: \.source.id) { news in
VStack {
VStack(alignment: .leading) {
Text(news.source.name ?? "")
Text(news.title)
Text(news.description ?? "")
}
}
}
.navigationTitle("Landmarks")
}
}
}
查看模型更新:
@Published var articles = [Article]()
let model = try JSONDecoder().decode(APIResponse.self,from: data)
//update properties on the main thread
DispatchQueue.main.async {
self.articles = model.articles
}