为啥我的 SwiftUI JSONDecoder 会出现致命错误?
Posted
技术标签:
【中文标题】为啥我的 SwiftUI JSONDecoder 会出现致命错误?【英文标题】:Why does my SwiftUI JSONDecoder give a fatal error?为什么我的 SwiftUI JSONDecoder 会出现致命错误? 【发布时间】:2021-04-25 18:32:43 【问题描述】:我正在开发一个 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)
【参考方案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
【讨论】:
以上是关于为啥我的 SwiftUI JSONDecoder 会出现致命错误?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 JsonDecoder 在尝试解析邮递员网址但处理其他网址时出现错误?
用于 API 的 JSONDecoder 和文本视图结构中的数据的问题