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

如何基于Codable协议按类型解码JSON至对应Collection对象

解决Codable根据collectionType动态解析data字段的问题

这是个很常见的动态类型解码场景,我来一步步帮你实现根据collectionType的值,把data字段解析成对应的[Item]或[Location]数组:

1. 用枚举封装不同的data类型

首先给Collection类添加一个枚举类型CollectionData,用来承载两种不同的data数组类型,既保证类型安全,又避免使用Any带来的类型歧义:

enum CollectionData: Codable {
    case items([Item])
    case locations([Location])
}

2. 修改Collection类并实现自定义解码

接下来调整你的Collection类,把data字段类型改为CollectionData,然后手动实现init(from decoder:)方法——在这个方法里我们先解析collectionType,再根据它的值去解码对应的data类型:

class Collection: NSObject, Codable {
    // MARK: - Properties
    let collectionType: String
    let collectionName: String
    let data: CollectionData

    // MARK: - CodingKeys
    private enum CodingKeys: String, CodingKey {
        case collectionType, collectionName, data // 别忘了加上data字段
    }

    // 自定义解码逻辑
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        // 先解析固定字段
        self.collectionType = try container.decode(String.self, forKey: .collectionType)
        self.collectionName = try container.decode(String.self, forKey: .collectionName)
        
        // 根据collectionType解析对应的data
        switch self.collectionType {
        case "item":
            let items = try container.decode([Item].self, forKey: .data)
            self.data = .items(items)
        case "location":
            let locations = try container.decode([Location].self, forKey: .data)
            self.data = .locations(locations)
        default:
            // 处理未知的collectionType,抛出明确的解码错误
            throw DecodingError.dataCorruptedError(
                forKey: .collectionType,
                in: container,
                debugDescription: "Unsupported collection type: \(self.collectionType)"
            )
        }
    }
}

你的Item和Location类不需要修改,保持原实现即可:

class Item: NSObject, Codable {
    // MARK: - Properties
    let itemTitle: String
    let itemSubtitle: String

    // MARK: - CodingKeys
    private enum CodingKeys: String, CodingKey {
        case itemTitle, itemSubtitle
    }
}

class Location: NSObject, Codable {
    // MARK: - Properties
    let locationName: String

    // MARK: - CodingKeys
    private enum CodingKeys: String, CodingKey {
        case locationName
    }
}

3. 使用解析后的对象

当你把JSON解码成[Collection]数组后,可以通过switch语句轻松处理不同类型的data:

// 假设jsonData是你的JSON数据
do {
    let collections = try JSONDecoder().decode([Collection].self, from: jsonData)
    
    for collection in collections {
        print("Collection name: \(collection.collectionName)")
        switch collection.data {
        case .items(let items):
            print("This is an item collection, count: \(items.count)")
            // 遍历处理Item对象
            for item in items {
                print("- Item: \(item.itemTitle) / \(item.itemSubtitle)")
            }
        case .locations(let locations):
            print("This is a location collection, count: \(locations.count)")
            // 遍历处理Location对象
            for location in locations {
                print("- Location: \(location.locationName)")
            }
        }
    }
} catch {
    print("Decoding error: \(error)")
}

为什么要这么做?

默认的Codable解码是静态的,无法根据其他字段的值动态调整解码类型。通过手动实现init(from decoder:),我们可以先获取collectionType的取值,再针对性地解码data字段,完美匹配你的JSON结构需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:27:27