首页 > 解决方案 > 使用 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
}
    
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()
    }
}

标签: iosjsonswiftswiftui

解决方案


有几个问题:

  1. 您的模型缺少一层。您的 JSON 有一个apps包含 的键FeaturedApps,但您的模型中没有任何内容反映这一点。我用过FeaturedAppsWrapper

  2. 因为idJSON 中不存在 ,所以您需要告诉编译器使用某些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()
    }
}

推荐阅读