ios - 使用 SwiftUI 将 JSON 解析为 HStack
问题描述
我已经完全放弃了,因为无论我做什么都找不到解决方案。
JSON:https ://github.com/MasonD3V/evoflight/raw/master/featuredapps.json
构建中没有错误,但是在启动应用程序后,我在控制台中遇到了这个错误:
致命错误:“试试!” 表达式意外引发错误:Swift.DecodingError.typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil)): file EvoFlight /FeaturedAPICall.swift,第 14 行
这是我的代码,以便您理解它。
- 主要课程的片段
struct ContentView: View {
...
@State var featuredApps: [FeaturedApps] = []
var body: some View {
ForEach(featuredApps) { app in
HStack(spacing: 10) {
}
}
.onAppear() {
featureApiCall().getApps { (app) in
self.featuredApps = app
}
}
struct FeaturedApps: Codable, Identifiable {
var id = UUID()
let image: String
let name: String
let category: String
let ipa: String
}
- FeaturedAPICall.swift
class featureApiCall {
func getApps(completion:@escaping ([FeaturedApps]) -> ()) {
guard let url = URL(string: "https://github.com/MasonD3V/evoflight/raw/master/featuredapps.json") else { return }
URLSession.shared.dataTask(with: url) { (data, _, _) in
let users = try! JSONDecoder().decode([FeaturedApps].self, from: data!)
print(users)
DispatchQueue.main.async {
completion(users)
}
}
.resume()
}
}
TLDR:出现“预期解码数组但找到字典”错误,我已经尝试了几次修复它。
编辑:我已经应用了一些推荐的更改。这是现在的代码。
// ContentView Code
struct ContentView: View {
...
@State var featuredApps: FeaturedAppsWrapper
var body: some View {
ForEach(featuredApps.apps) { app in
HStack(spacing: 10) {
}
}
.onAppear() {
featureApiCall().getApps { (app) in
self.featuredApps = app
}
}
struct FeaturedApps: Codable, Identifiable {
var id = UUID()
let image: String
let name: String
let category: String
let ipa: String
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView() // Missing argument for parameter 'featuredApps' in call error
}
}
struct FeaturedAppsWrapper :Codable {
var apps : [FeaturedApps]
init() {
}
}
struct FeaturedApps: Codable, Identifiable {
var id = UUID()
let image: String
let name: String
let category: String
let ipa: String
enum CodingKeys : String, CodingKey {
case image, name, category, ipa
}
}
// FeaturedApiCall.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, _, _) in
do {
let wrapper = try JSONDecoder().decode(FeaturedAppsWrapper.self, from: data!)
let users = wrapper.apps
print(users)
} catch {
print(error)
}
}
.resume()
}
}
解决方案
有几个问题:
您的模型缺少一层。您的 JSON 有一个
apps
包含 的键FeaturedApps
,但您的模型中没有任何内容反映这一点。我用过FeaturedAppsWrapper
。因为
id
JSON 中不存在 ,所以您需要告诉编译器使用某些CodingKeys
,不包括id
。
struct FeaturedAppsWrapper :Codable {
var apps : [FeaturedApps]
}
struct FeaturedApps: Codable, Identifiable {
var id = UUID()
let image: String
let name: String
let category: String
let ipa: String
enum CodingKeys : String, CodingKey {
case image, name, category, ipa
}
}
do {
let wrapper = try JSONDecoder().decode(FeaturedAppsWrapper.self, from: data!)
let users = wrapper.apps
print(users)
} catch {
print(error)
}
最后,你最好改掉使用!
强制解包的习惯try
——如果出现问题,它会保证崩溃。do/try/catch
例如,我用过try!
鉴于您的更新,这是我将如何处理它:
struct FeaturedAppsWrapper :Codable {
var apps : [FeaturedApps]
}
struct FeaturedApps: Codable, Identifiable {
var id = UUID()
let image: String
let name: String
let category: String
let ipa: String
enum CodingKeys : String, CodingKey {
case image, name, category, ipa
}
}
struct ContentView: View {
@StateObject private var apiManager = ApiManager()
var body: some View {
ForEach(apiManager.featuredApps.apps) { app in
HStack(spacing: 10) {
Text(app.name)
}
}
.onAppear() {
apiManager.getApps()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
class ApiManager : ObservableObject {
@Published var featuredApps = FeaturedAppsWrapper(apps: [])
func getApps() {
guard let url = URL(string: "https://github.com/MasonD3V/evoflight/raw/master/featuredapps.json") else { return }
URLSession.shared.dataTask(with: url) { (data, _, _) in
do {
let wrapper = try JSONDecoder().decode(FeaturedAppsWrapper.self, from: data!)
DispatchQueue.main.async {
self.featuredApps = wrapper
}
} catch {
print(error)
}
}
.resume()
}
}
推荐阅读
- java - 解决“多个 Jar 文件”又名“从多个位置扫描”
- android - viewpager2 与片段,其中 viewpager2 在销毁第一个父亲片段后也没有被销毁
- jquery - 如何使用 jquery 将“2020-10-08 09:38:08”转换为 2020 年 3 月格式
- simple-injector - 使用 Lifestyle.Singleton 时注册的 COM 接口无法解析
- algorithm - 使用重心将任何图形转换为平面的复杂性
- perl - 如何做 Perl 状态机(FSM)来解析比特流(字节序列)?
- flutter - 使用异步更新提供程序后,具有未来构建器的小部件不会删除小部件
- azure - 如何在 Azure 云计费导出中查找 ServiceName
- javascript - The "listener" argument must be of type function. Received undefined
- r - 在ggplot中设置ylims时如何删除小数位?