You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Decodable解析数组遇类型不匹配错误,求重写协议方案

Fixing the "Expected to decode Dictionary<String, Any> but found an array instead" Decoding Error

Hey there! Let's work through fixing this decoding issue you're hitting. The error message is pretty straightforward: your decoder was expecting a dictionary (single object) for the results field, but instead it found an array of objects in the JSON. Here's how to resolve this, either by adjusting your model structure or manually handling decoding if you need special behavior.

First: Confirm Your JSON Structure

Let's use a common example of what your JSON might look like (since you didn't share it directly):

{
  "results": [
    {
      "slotId": "morning_01",
      "timeRange": "9:00-10:00",
      "available": true
    },
    {
      "slotId": "afternoon_01",
      "timeRange": "14:00-15:00",
      "available": false
    }
  ]
}

In this case, results is an array of slot objects—but if your model defined results as a single Slots instance (a dictionary/object), that's exactly why you're getting the error.

Solution 1: Adjust Your Model to Match the JSON

The simplest fix is updating your model to expect an array for results:

Step 1: Keep Your Slots Struct (it's good as-is)

struct Slots: Decodable {
    let slotId: String
    let timeRange: String
    let available: Bool
    // Add any other properties from your JSON
}

Step 2: Create an Outer Response Struct

You need a top-level struct to represent the full JSON response, where results is an array of Slots:

struct SlotResponse: Decodable {
    let results: [Slots] // This is the key change—array instead of single object
}

Step 3: Decode the Response Normally

Now decode using SlotResponse.self instead of trying to decode Slots directly:

do {
    let decoder = JSONDecoder()
    // Assume `jsonData` is your raw JSON data
    let response = try decoder.decode(SlotResponse.self, from: jsonData)
    print("Successfully decoded \(response.results.count) slots!")
} catch {
    print("Decoding failed: \(error.localizedDescription)")
}

Solution 2: Manually Decode if You Need a Single Slot (e.g., Array Has One Item)

If your JSON returns an array but you only care about the first slot (or need to treat it as a single object), override the init(from:) method to handle this:

struct SlotResponse: Decodable {
    let results: Slots // We want a single Slots instance, not an array

    enum CodingKeys: String, CodingKey {
        case results
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        // First decode the array from JSON
        let slotsArray = try container.decode([Slots].self, forKey: .results)
        
        // Ensure the array has at least one item
        guard let firstSlot = slotsArray.first else {
            throw DecodingError.dataCorruptedError(
                forKey: .results,
                in: container,
                debugDescription: "Results array is empty—expected at least one slot"
            )
        }
        
        self.results = firstSlot
    }
}

This way, the decoder handles the array from JSON, but you end up with a single Slots instance in your model.

Key Takeaway

The root issue is a type mismatch between your model and the JSON. Double-check that every field in your model matches the JSON's structure:

  • If JSON has an array, use [Type] in your model
  • If JSON has a single object, use Type directly
  • For edge cases, override init(from:) to customize decoding logic

内容的提问来源于stack exchange,提问作者Xcoder

火山引擎 最新活动