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

Swift中如何通过Decodable对象将任意JSON值解码为字符串类型

解决方案

你遇到的问题是Swift内置的JSONDecoder默认严格匹配JSON类型,数值类型(整数、浮点数)无法直接解码为String类型属性,以下是两种可直接落地的实现方案:

方案1:手动实现Decodable初始化(仅当前结构体适用)

适合只有单个结构体需要该转换规则的场景,核心逻辑是对每个字段尝试解码不同类型,统一转为字符串存储,避免精度丢失:

struct StockNFS: Decodable {
    let name: String?
    let price: String?
    let no: String?
    let id: String?
    let amount: String?
    
    enum CodingKeys: String, CodingKey {
        case name, price, no, id, amount
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try container.decodeIfPresent(String.self, forKey: .name)
        price = try container.decodeStringLossless(forKey: .price)
        no = try container.decodeStringLossless(forKey: .no)
        id = try container.decodeIfPresent(String.self, forKey: .id)
        amount = try container.decodeStringLossless(forKey: .amount)
    }
}

// 扩展解码容器复用转换逻辑
extension KeyedDecodingContainer {
    func decodeStringLossless(forKey key: Key) throws -> String? {
        // 优先直接取字符串
        if let str = try? decodeIfPresent(String.self, forKey: key) {
            return str
        }
        // 尝试取整数转字符串
        if let intVal = try? decodeIfPresent(Int.self, forKey: key) {
            return String(intVal)
        }
        // 尝试取十进制数转字符串(精度远高于Double,适合超长数值场景)
        if let decimalVal = try? decodeIfPresent(Decimal.self, forKey: key) {
            return NSDecimalNumber(decimal: decimalVal).stringValue
        }
        return nil
    }
}

方案2:属性包装器实现(多结构体复用场景)

如果项目中多个结构体都需要统一转字符串的解码规则,可以封装属性包装器减少重复代码:

@propertyWrapper
struct StringLossless: Decodable {
    var wrappedValue: String?
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let str = try? container.decode(String.self) {
            wrappedValue = str
        } else if let intVal = try? container.decode(Int.self) {
            wrappedValue = String(intVal)
        } else if let decimalVal = try? container.decode(Decimal.self) {
            wrappedValue = NSDecimalNumber(decimal: decimalVal).stringValue
        } else {
            wrappedValue = nil
        }
    }
}

// 使用时只需给属性加包装器,无需自定义初始化方法
struct StockNFS: Decodable {
     @StringLossless var name: String?
     @StringLossless var price: String?
     @StringLossless var no: String?
     @StringLossless var id: String?
     @StringLossless var amount: String?
}

两种方案都完全避免了浮点数存储导致的精度异常问题,拿到的字符串可以直接用于UI展示,不需要额外转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 13:36:09