在 Swift 中解析 JSON 错误:预期解码数组<Any>但找到了字典

问题描述 投票:0回答:1

我正在尝试解码这个名为

Menu.json

的 JSON
[
  {
    "day": "Monday",
    "locationName": "Memorial Union Quad",
    "coordinate": [38.54141, -121.74845],
    "menu": {
        "Penne Pasta w/ Bolognese" : ["🌾","🐷"],
        "Penne Pasta w/ Roasted Mushrooms" : ["🌾","V"]
    }
  },
  {
    "day": "Tuesday",
    "locationName": "International Center",
    "coordinate": [38.54540, -121.75494],
    "menu": {
        "Beef & Lamb Gyro" : ["🌾","🫛", "🥛"],
        "Edamame Hummus w/ Veggies" : ["🫛","🥛", "SE", "VE"]
    }
  },
  {
    "day": "Wednesday",
    "locationName": "Storer Hall",
    "coordinate": [38.54114, -121.75461],
    "menu": {
        "Seafood Salad Tostada" : ["🥚","🦐", "🫛", "🐟"],
        "Southwest Black Bean Tostada" : ["V"]
    }
  },
  {
    "day": "Thursday",
    "locationName": "Orchard Park",
    "coordinate": [38.544828, -121.765170],
    "menu": {
        "Teriyaki Beef w/ Stir Fry Noodles" : ["🌾","🫛", "SE"],
        "Teriyaki Tofu w/ Veggie Stir Fry" : ["🌾","🫛", "SE","V"]
    }
  },
   {
    "day": "Friday",
    "locationName": "Memorial Union Quad",
    "coordinate": [38.54141, -121.74845],
    "menu": {
        "Soy Ciltrano Lime Chicken" : ["🌾","🫛"],
        "Southwest Tofu" : ["🫛","V"]
    }
  }
]

这就是我在 Swift 中建模数据的方式:

import Foundation
import OrderedCollections

struct Menu : Codable, Hashable {
    var id: UUID { UUID() }
    let day: String
    let locationName: String
    let coordinate: [Double]
    let menu: OrderedDictionary<String, [String]>
    
    func getTodaysLocation(_ today: String)-> String{
        if today == day{
            return locationName
        }
        return ""
    }
    
    
}

这就是我解码数据的方式:

import Foundation

extension Bundle {
    func decode(_ file: String) -> [Menu] {
        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()

        do {
            return try decoder.decode([Menu].self, from: data)
        } catch DecodingError.keyNotFound(let key, let context) {
            fatalError("Failed to decode \(file) from bundle due to missing key '\(key.stringValue)' – \(context.debugDescription)")
        } catch DecodingError.typeMismatch(_, let context) {
            fatalError("Failed to decode \(file) from bundle due to type mismatch – \(context.debugDescription)")
        } catch DecodingError.valueNotFound(let type, let context) {
            fatalError("Failed to decode \(file) from bundle due to missing \(type) value – \(context.debugDescription)")
        } catch DecodingError.dataCorrupted(_) {
            fatalError("Failed to decode \(file) from bundle because it appears to be invalid JSON.")
        } catch {
            fatalError("Failed to decode \(file) from bundle: \(error.localizedDescription)")
        }
    }
}

但我收到以下错误:“由于类型不匹配,无法从捆绑包中解码 Menu.json – 预期解码数组,但找到了字典。”

我对数据的建模是否正确?还是Bundle中的解码功能有问题?

我尝试修改数据建模方式,但我刚接触 JSON,所以我不完全确定问题是否在于我在 Swift 中建模 JSON 的方式。

ios json swift swiftui
1个回答
0
投票

OrderedCollection
的文档描述了这种类型所需的结构:

OrderedDictionary
希望其内容在未加密的容器中被编码为交替键值对。

即如果你想使用

OrderedCollection
,你必须使用不同的JSON结构:

[
    {
        "day": "Monday",
        "locationName": "Memorial Union Quad",
        "coordinate": [38.54141, -121.74845],
        "menu": [
            "Penne Pasta w/ Bolognese",
            ["🌾","🐷"],
            "Penne Pasta w/ Roasted Mushrooms",
            ["🌾","V"]
        ]
    }
]    

一般来说,如果项目的顺序很重要,则不应使用 JSON 对象作为“菜单”,而应使用数组。

有多种不同的方式来构造或解码数据。这是一种替代方案:

struct Menu: Codable, Hashable {
    var id: UUID { UUID() }

    let day: String
    let locationName: String
    let coordinate: [Double]
    let menu: [MenuItem]
}

struct MenuItem: Codable, Hashable {
    let description: String
    let ingredients: [String]
}

JSON 具有以下结构:

[
    {
        "day": "Monday",
        "locationName": "Memorial Union Quad",
        "coordinate": [38.54141, -121.74845],
        "menu": [
            {
                "description": "Penne Pasta w/ Bolognese",
                "ingredients": ["🌾","🐷"]
            },
            {
                "description": "Penne Pasta w/ Roasted Mushrooms",
                "ingredients": ["🌾","V"]
            }
        ]
    }
]
© www.soinside.com 2019 - 2024. All rights reserved.