复活节快乐!
我正在构建一个应用程序来接收3个不同的JSON文件。它们中的每一个都由相同的数字组成,作为赢得一场比赛的选项(飞镖出局)。
示例:
{
"checkoutOptions1": [
{
"170": {
"out": "T20 T20 DB"
},
"167": {
"out": "T20 T19 DB"
},
"164": {
"out": "T20 T18 DB"
},
"161": {
"out": "T20 T17 DB"
},
"160": {
"out": "T20 T20 D20"
}
}
]
}其他两个文件是相同的数字,但给出的字符串完全不同。
我有一个名为"Out“的结构,它允许从有关的json文件中获取"out”。
struct Out: Codable {
let out: String
}我的捆绑解码器的定义如下:
extension Bundle {
func decode(_ file: String) -> [String: Out] {
guard let url = self.url(forResource: file, withExtension: nil) else {
fatalError("Failed to locate \(file) in bundle.")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(file) from bundle.")
}
let decoder = JSONDecoder()
guard let loaded = try? decoder.decode([String: Out].self, from: data ) else {
fatalError("Failed to decode \(file) from bundle.")
}
return loaded
}
}这不管用。这是我第一次处理JSON解码器。寻找一些洞察力看看我是否有正确的想法。提亚
发布于 2022-04-17 23:32:34
您的模型(Out)与您显示的json数据不匹配。试着做这样的事情:
struct Checkout: Codable {
var checkoutOptions1: [[String : Out]]
}
struct Out: Codable {
var out: String
}和
guard let loaded = try? decoder.decode(Checkout.self, from: data) else {
fatalError("Failed to decode \(file) from bundle.")
}编辑-1:下面是如何使用模型的一个简单示例。
struct Checkout: Codable {
var checkoutOptions1: [[String : Out]]
}
struct Out: Codable {
var out: String
}
struct ContentView: View {
var body: some View {
Text("testing")
.onAppear {
let json = """
{
"checkoutOptions1": [
{
"170": {
"out": "T20 T20 DB"
},
"167": {
"out": "T20 T19 DB"
},
"164": {
"out": "T20 T18 DB"
},
"161": {
"out": "T20 T17 DB"
},
"160": {
"out": "T20 T20 D20"
}
}
]
}
"""
let data = json.data(using: .utf8)!
let loaded = try? JSONDecoder().decode(Checkout.self, from: data)
print("\n----> loaded: \(loaded?.checkoutOptions1) \n")
}
}
}另一种选择是:
extension Bundle {
func decode<T: Codable>(_ file: String) -> T {
guard let url = Bundle.main.url(forResource: file, withExtension: nil) else {
fatalError("Could not find \(file) in the project")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Could not load \(file) in the project")
}
do {
let loadedData = try JSONDecoder().decode(T.self, from: data)
return loadedData
} catch {
print(error)
fatalError("Could not decode \(file) in the project")
}
}
}
struct ContentView: View {
var body: some View {
Text("testing")
.onAppear {
let result: Checkout = Bundle().decode("Dart.json")
print("\n----> result: \(result) ")
print("\n----> checkoutOptions1: \(result.checkoutOptions1) ")
print("\n----> first: \(result.checkoutOptions1.first) ")
print("\n----> 170: \(result.checkoutOptions1.first?["170"]) ")
print("\n----> 170 out: \(result.checkoutOptions1.first?["170"]?.out) ")
}
}
}编辑-2:
我不知道如何打分飞镖游戏,但使用@JoakimDanielson的建议,您可以将json数据重组为:
{
"options": [
{
"key": "170",
"out": "T20 T20 DB"
},
{
"key": "167",
"out": "T20 T19 DB"
},
{
"key": "164",
"out": "T20 T18 DB"
},
{
"key": "161",
"out": "T20 T17 DB"
},
{
"key": "160",
"out": "T20 T20 D20"
}
]
}并使用此示例代码将其解码为更易于管理的结构。
extension Bundle {
func decode<T: Codable>(_ file: String) -> T? { // <-- here optional
guard let url = Bundle.main.url(forResource: file, withExtension: nil) else {
print("Could not find \(file) in the project")
return nil
}
guard let data = try? Data(contentsOf: url) else {
print("Could not load \(file) in the project")
return nil
}
do {
return try JSONDecoder().decode(T.self, from: data)
} catch {
print("Could not decode \(file) in the project")
return nil
}
}
}
struct ContentView: View {
@State var options: [Option] = []
var body: some View {
Button("load data", action: {
if let checkout: CheckOut = Bundle().decode("Dart.json") {
options = checkout.options
}
}).buttonStyle(.bordered)
List {
ForEach(options) { option in
Text("key: \(option.key) out: \(option.out) ")
}
}
}
}
struct CheckOut: Codable {
let options: [Option]
}
struct Option: Identifiable, Codable {
let id = UUID()
let key, out: String
}发布于 2022-04-17 23:41:18
将decode包装到try catch并打印错误总是有帮助的。错误会告诉你问题出在哪里。如果你这样做的话
do {
let loaded = try decoder.decode([String: Out].self, from: data )
return loaded
} catch {
print(error)
fatalError("Failed to decode \(file) from bundle.")
}然后,它将打印如下:
typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "checkoutOptions1", intValue: nil)], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))实际上,如果仔细观察,那么JSON的结构实际上是这样的:[String: [[String: Out]]]。checkoutOptions1的值是一个数组,包含一个[String: Out]类型的字典。
因此,如果您将代码更改为:
let loaded = try decoder.decode([String: [[String: Out]]].self, from: data )它将取得成功,尽管结果并不容易处理,因为您的Out结构将被隐藏在字典中的几个层次中。
改善这种情况的一种方法是定义以下模型:
struct Options: Codable {
let checkoutOptions1: [[String: Out]]
}然后将解码行更改为:
let loaded = try decoder.decode(Options.self, from: data)loaded.checkoutOptions1[0]将包含[String: Out]类型的字典。
https://stackoverflow.com/questions/71906055
复制相似问题