You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 5如何解码含API自动生成数字ID键的无顶层键JSON

Fixing Dynamic Key JSON Decoding in Swift 5

Hey, let's work through your JSON decoding problem. The core issue here is that your current Rooms struct doesn't align with the dynamic structure of your JSON—where top-level keys are unpredictable room IDs, and their values are the room objects.

First, Let's Understand the JSON Structure

Your simplified JSON looks like this:

{ 
  "1": { "name": "Tea room", "description": "A room for tea" }, 
  "2": { "name": "Playground", "description": "Here you can play all day long" }, 
  "3": { "name": "Kitchen", "description": "Hungry persons can go here" } 
}

This is essentially a dictionary where keys are integers (formatted as strings) and values are room objects. Your original Rooms struct expects fields like id and rooms, which don't exist in the JSON—hence the decoding failure.


Solution 1: Decode Directly to a Dictionary (Simplest Approach)

The quickest fix is to decode the JSON directly into a [Int: Room] dictionary. This lets you access each room by its ID immediately.

First, clean up your Room struct (you can omit the CodingKeys if property names match the JSON keys exactly):

struct Room: Decodable {
    let name: String
    let description: String
}

Then perform the decoding:

do {
    let roomsDictionary = try JSONDecoder().decode([Int: Room].self, from: jsonResult)
    
    // Iterate through the dictionary to get IDs and rooms
    for (roomId, room) in roomsDictionary {
        print("Room ID: \(roomId), Name: \(room.name), Description: \(room.description)")
    }
} catch {
    print("Decoding failed: \(error.localizedDescription)")
}

Solution 2: Custom Rooms Struct with Custom Decoding

If you prefer to encapsulate the rooms in a custom struct (for better organization in your code), you can implement custom decoding logic to handle the dynamic keys.

First, define the Rooms struct with a custom init(from:) method:

struct Rooms: Decodable {
    // Store rooms as an array of tuples (ID + Room) for easy access
    let roomList: [(id: Int, details: Room)]
    
    init(from decoder: Decoder) throws {
        // Get the top-level keyed container
        let container = try decoder.container(keyedBy: DynamicCodingKeys.self)
        var rooms = [(Int, Room)]()
        
        // Iterate over all dynamic keys
        for key in container.allKeys {
            // Convert the string key to an integer ID
            guard let roomId = Int(key.stringValue) else {
                throw DecodingError.dataCorrupted(
                    DecodingError.Context(
                        codingPath: [key],
                        debugDescription: "Room ID '\(key.stringValue)' is not a valid integer"
                    )
                )
            }
            
            // Decode the Room object for this key
            let room = try container.decode(Room.self, forKey: key)
            rooms.append((roomId, room))
        }
        
        self.roomList = rooms
    }
    
    // Custom coding keys to handle dynamic string keys
    private struct DynamicCodingKeys: CodingKey {
        let stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        
        let intValue: Int?
        init?(intValue: Int) {
            self.stringValue = String(intValue)
            self.intValue = intValue
        }
    }
}

// Reuse the same Room struct from Solution 1
struct Room: Decodable {
    let name: String
    let description: String
}

Then decode using this struct:

do {
    let rooms = try JSONDecoder().decode(Rooms.self, from: jsonResult)
    
    for roomEntry in rooms.roomList {
        print("Room ID: \(roomEntry.id), Name: \(roomEntry.details.name)")
    }
} catch {
    print("Decoding failed: \(error.localizedDescription)")
}

Why Your Original Code Failed

Your original Rooms struct expected the JSON to have top-level fields id and rooms, but your actual JSON has dynamic keys (room IDs) as the top-level structure. The decoder couldn't find the fields your struct was looking for, leading to a decoding error.

Choose the solution that best fits your workflow: the dictionary approach is great for quick, straightforward use, while the custom struct adds structure for larger codebases.

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 07:29:08