使用Decodable解析数组遇类型不匹配错误,求重写协议方案
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
Typedirectly - For edge cases, override
init(from:)to customize decoding logic
内容的提问来源于stack exchange,提问作者Xcoder




