SwiftUI解析JSON渲染HStack时出现「期望解码数组却找到字典」错误
错误原因说明
- 初始解码错误:目标JSON根节点为字典结构,外层包含
apps键对应应用数组,直接解码数组类型会触发类型不匹配错误 - 预览参数缺失错误:
@State修饰的featuredApps属性未设置默认初始值,Swift结构体要求所有属性必须完成初始化,因此预览调用时会要求传入参数 - 补充遗漏点:你修改后的网络请求代码中,解码成功后未调用
completion闭包,会导致界面无法收到返回数据
完整修复代码
1. 数据模型与ContentView代码
import SwiftUI struct ContentView: View { // 给@State属性设置默认初始值,解决预览参数缺失问题 @State var featuredApps: FeaturedAppsWrapper = FeaturedAppsWrapper() var body: some View { ScrollView(.horizontal) { HStack(spacing: 10) { ForEach(featuredApps.apps) { app in // 这里填充你要的HStack内容,示例可自行调整 VStack { AsyncImage(url: URL(string: app.image)) { image in image.resizable() } placeholder: { Color.gray } .frame(width: 60, height: 60) .cornerRadius(12) Text(app.name) .font(.caption) Text(app.category) .font(.caption2) .foregroundColor(.gray) } } } .padding(.horizontal) } .onAppear() { FeatureApiCall().getApps { wrapper in self.featuredApps = wrapper } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { // 现在属性有默认值,不需要传参 ContentView() } } // 外层包装模型,对应JSON根字典 struct FeaturedAppsWrapper : Codable { var apps : [FeaturedApps] // 空初始化方法保留,用于默认值创建 init() { self.apps = [] } } // 应用数据模型 struct FeaturedApps: Codable, Identifiable { // id为本地生成,不需要参与解码 var id = UUID() let image: String let name: String let category: String let ipa: String // 明确指定参与解码的字段,排除id enum CodingKeys : String, CodingKey { case image, name, category, ipa } }
2. FeaturedAPICall.swift代码
import Foundation // 类名首字母大写符合Swift规范 class FeatureApiCall { func getApps(completion:@escaping (FeaturedAppsWrapper) -> ()) { guard let url = URL(string: "https://github.com/MasonD3V/evoflight/raw/master/featuredapps.json") else { return } URLSession.shared.dataTask(with: url) { data, _, error in // 增加错误处理,避免强制解包崩溃 guard let data = data, error == nil else { print("网络请求错误: \(error?.localizedDescription ?? "未知错误")") return } do { let wrapper = try JSONDecoder().decode(FeaturedAppsWrapper.self, from: data) print("解码成功,应用数量: \(wrapper.apps.count)") // 补全completion调用,回到主队列更新UI DispatchQueue.main.async { completion(wrapper) } } catch { print("解码错误: \(error)") } } .resume() } }
内容的提问来源于stack exchange,提问作者Mason
相关产品推荐
相关产品推荐

