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

解码可空异构字典:KeyedDecodingContainer扩展实现求助

解决异构对象为键的字典解码问题

首先,我注意到你现有的字典解码代码存在核心问题:你用了nestedUnkeyedContainer处理字典,但逻辑上没有适配键值对结构——而且原生JSON不支持非字符串作为字典键,这类场景下后端通常会把异构键的字典序列化为包含key和value字段的对象数组(比如[{"key": {...}, "value": 1.0}, ...])。

下面是适配这个场景的完整解决方案,同时复用你已实现的异构对象解码逻辑:

1. 定义辅助结构体与CodingKeys

先创建辅助结构体来解码数组中的单个键值对条目,同时定义对应的CodingKeys:

// 辅助结构体,用于解码JSON中的单个字典条目
private struct DictionaryEntry<T: Decodable>: Decodable {
    let key: T
    let value: CGFloat
}

private extension KeyedDecodingContainer {
    // 用于解析键值对条目的CodingKeys
    enum EntryCodingKeys: String, CodingKey {
        case key, value
    }
}

2. 修正后的字典解码方法

我们先解码数组形式的条目,再将其转换为Swift字典,同时复用你已有的异构对象解码逻辑:

func decodeDictIfPresent<T : Decodable, U : ClassFamily>(family: U.Type, forKey key: K) throws -> [T: CGFloat]? {
    do {
        // 获取存储字典的数组容器
        var arrayContainer = try self.nestedUnkeyedContainer(forKey: key)
        var entries = [DictionaryEntry<T>]()
        
        while !arrayContainer.isAtEnd {
            // 解码单个键值对的容器
            let entryContainer = try arrayContainer.nestedContainer(keyedBy: EntryCodingKeys.self)
            
            // 复用你已实现的单个异构对象解码逻辑来解析key
            guard let decodedKey = try entryContainer.decodeIfPresent(family: family, forKey: .key) else {
                continue // 跳过无法解析的条目
            }
            
            // 解码CGFloat类型的value
            let decodedValue = try entryContainer.decode(CGFloat.self, forKey: .value)
            
            entries.append(DictionaryEntry(key: decodedKey, value: decodedValue))
        }
        
        // 将数组转换为字典:用reduce保留最后一个重复key的值
        return entries.reduce(into: [T: CGFloat]()) { result, entry in
            result[entry.key] = entry.value
        }
        // 如果要严格保证key唯一,用下面的代码(重复key会抛出错误)
        // return Dictionary(uniqueKeysWithValues: entries.map { ($0.key, $0.value) })
    } catch DecodingError.keyNotFound, DecodingError.valueNotFound {
        return nil
    }
}

关键注意事项

  • JSON结构匹配:确保后端返回的JSON结构是[{"key": {...}, "value": 数值}, ...]的形式,如果你的JSON结构不同(比如直接用字符串键对应异构对象的ID),需要调整解码逻辑先通过ID映射到异构对象。
  • 异构类型兼容性:确保T是所有异构对象类型的共同父类或协议,并且U.getType()返回的类型可以安全转换为T.Type,否则会跳过无法解析的条目。
  • 重复key处理:上面的代码用reduce保留最后一个重复key的值,如果你的场景不允许重复key,可以改用Dictionary(uniqueKeysWithValues:),但重复key会抛出解码错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 21:02:30