【问题标题】:Why does my SwiftUI JSONDecoder give a fatal error?为什么我的 SwiftUI JSONDecoder 会出现致命错误?
【发布时间】:2023-04-10 14:27:02
【问题描述】:

我正在开发一个 SwiftUI 应用程序,该应用程序应该从 JSON 文件加载问题并将它们一一展示给用户。我关注了a tutorial 如何将JSON-data 加载到视图中,但它不起作用。 JSONDecoder 似乎失败了,有人知道为什么吗?

这是我的代码:

CodableBundleExtension.swift

import Foundation

extension Bundle {
    func decode(_ file: String) -> [Question] {
        // Locate the JSON-file.
        guard let url = self.url(forResource: file, withExtension: nil) else {
            fatalError("Failed to locate \(file) in bundle.")
        }
        
        // Create a property for the data
        guard let data = try? Data(contentsOf: url) else {
            fatalError("Failed to load \(file) from bundle.")
        }
        
        // Create a decoder
        let decoder = JSONDecoder()
        
        // Create a property for the decoded data
        guard let loaded = try? decoder.decode([Question].self, from: data) else {
            fatalError("Failed to decode \(file) from bundle.")
        }
        
        // Return the decoded data
        return loaded
    }
}

Questions.swift

import SwiftUI

struct Question: Codable, Identifiable {
    let id: Int
    let question: String
    let gamemode: Int
    let min_players: Int
    let max_platers: Int
    let question_type: Int
    let language: String
    
}

ContentView.swift

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        let questions : [Question] = Bundle.main.decode("questions.json")
        
        ForEach(questions) { item in
            Text(item.question)
        }
        ZStack {
            LinearGradient(
                gradient: Gradient(
                            colors: [.blue, .white]),
                            startPoint: .topLeading,
                            endPoint: .bottomTrailing)
                .edgesIgnoringSafeArea(.all)
            VStack {
                Text("The Questions App")
                    .font(.system(size: 36))
                    .fontWeight(.bold)
                    .foregroundColor(.white)
                    .padding(.top, 40)
                    .padding(.bottom, 40)
                VStack {
                    Image(systemName: "homepod")
                        .renderingMode(.original)
                        .resizable()
                        .frame(width: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/, height: 140, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
                        .aspectRatio(contentMode: .fit)
                        
                    Spacer()
                    
                    Button {
                        print("tapped")
                    } label: {
                        Text("Click Me")
                            .font(.system(size: 32))
                            .fontWeight(.medium)
                            .foregroundColor(.blue)
                            .frame(width: 200, height: 70, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
                            .background(Color.white)
                            .cornerRadius(20)
                            
                    }
                    
                    Spacer()
                }
                
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

questions.json

[
    {
        "id": 1,
        "question": "Testquestion 1",
        "gamemode": 1,
        "min_players": 2,
        "max_players": 4,
        "question_type": 1,
        "language": "NL"
    },
    {
        "id": 2,
        "question": "Testquestion 2",
        "gamemode": 1,
        "min_players": 2,
        "max_players": 99,
        "question_type": 2,
        "language": "NL"
    }
]

这是错误:

Fatal error: Failed to decode questions.json from bundle.: file Drinking_App_V1/CodableBundleExtension.swift, line 27
2021-04-25 20:19:29.617268+0200 Questions App V1[13218:851770] Fatal error: Failed to decode questions.json from bundle.: file Questions_App_V1/CodableBundleExtension.swift, line 27
(lldb) 

【问题讨论】:

  • 而不是 try? 使用 do-catch 并打印错误
  • @Andrew 我如何用这段代码做到这一点?我对 Swift 很陌生..
  • do { let loaded = try decoder.decode(...) } catch { print(error) }docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html
  • 第 32 行(已加载返回)现在给出错误:“无法将 'Bool' 类型的返回表达式转换为返回类型 '[Question]'”。我的代码是: do { let loaded = try decoder.decode([Question].self, from: data) } catch { print(error) }

标签: json swiftui jsondecoder


【解决方案1】:

如果你使用 do/catch:

extension Bundle {
    func decode(_ file: String) -> [Question] {
        // Locate the JSON-file.
        guard let url = self.url(forResource: file, withExtension: nil) else {
            fatalError("Failed to locate \(file) in bundle.")
        }
        
        do {
            let data = try Data(contentsOf: url)
            let decoder = JSONDecoder()
            return try decoder.decode([Question].self, from: data)
        } catch {
            print(error)
            fatalError("Failed to decode \(file) from bundle.")
        }
    }
}

你会看到这个错误:

keyNotFound(CodingKeys(stringValue: "max_platers", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"max_platers\", intValue: nil) (\"max_platers\").", underlyingError: nil))

这告诉您,max_platers 在 JSON 中没有任何值,如您所见,这是 max_players 的拼写错误。

将您的模型转换为:

struct Question: Codable, Identifiable {
    let id: Int
    let question: String
    let gamemode: Int
    let min_players: Int
    let max_players: Int //<-- Here
    let question_type: Int
    let language: String
}

【讨论】:

    猜你喜欢
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 2023-02-08
    • 2013-11-27
    • 2012-01-17
    • 2021-04-08
    • 2013-02-11
    相关资源
    最近更新 更多