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

Swift iOS开发:API返回message_id类型不一致的问题问询

问题解答:Swift处理API返回的message_id类型不一致问题

你同事的说法是否正确?

不完全正确。Swift的Codable框架支持自定义解析逻辑,完全可以在解析JSON的过程中处理message_id时而为字符串、时而为整数的情况,不需要提前将转换器的预期类型固定为单一类型。

解决方案

下面提供两种常用的Swift解析方案,都能将message_id统一转为String类型:

方法一:使用枚举作为中间类型处理多类型

定义一个支持String和Int类型的枚举,通过它将不同类型的message_id统一转为String:

// 定义支持多类型的枚举,用于解析message_id
enum MultiTypeString: Codable {
    case string(String)
    case int(Int)
    
    // 提供统一的String取值
    var stringValue: String {
        switch self {
        case .string(let str): return str
        case .int(let num): return String(num)
        }
    }
    
    // 自定义解码逻辑
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let str = try? container.decode(String.self) {
            self = .string(str)
        } else if let num = try? container.decode(Int.self) {
            self = .int(num)
        } else {
            throw DecodingError.dataCorruptedError(in: container, debugDescription: "Expected String or Int for message_id")
        }
    }
    
    // 编码逻辑(如果需要回传数据)
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let str): try container.encode(str)
        case .int(let num): try container.encode(num)
        }
    }
}

// 聊天数据模型
struct ChatMessage: Codable {
    let id: Int
    private let message_id: MultiTypeString
    let last_sender_id: String
    let subject: RenderedContent
    let excerpt: RenderedContent
    let message: RenderedContent
    let date: String
    
    // 对外暴露统一的String类型messageId
    var messageId: String {
        message_id.stringValue
    }
}

// 嵌套的内容模型
struct RenderedContent: Codable {
    let rendered: String
}

方法二:在模型的自定义初始化方法中直接处理

直接在ChatMessage的init(from decoder:)方法里处理message_id的类型判断和转换:

struct ChatMessage: Codable {
    let id: Int
    let messageId: String // 最终统一为String类型
    let last_sender_id: String
    let subject: RenderedContent
    let excerpt: RenderedContent
    let message: RenderedContent
    let date: String
    
    // 定义CodingKeys映射JSON字段
    enum CodingKeys: String, CodingKey {
        case id, message_id, last_sender_id, subject, excerpt, message, date
    }
    
    // 自定义解码逻辑
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        // 解析其他固定类型的字段
        id = try container.decode(Int.self, forKey: .id)
        last_sender_id = try container.decode(String.self, forKey: .last_sender_id)
        subject = try container.decode(RenderedContent.self, forKey: .subject)
        excerpt = try container.decode(RenderedContent.self, forKey: .excerpt)
        message = try container.decode(RenderedContent.self, forKey: .message)
        date = try container.decode(String.self, forKey: .date)
        
        // 处理message_id的类型不一致
        if let strId = try? container.decode(String.self, forKey: .message_id) {
            messageId = strId
        } else if let intId = try? container.decode(Int.self, forKey: .message_id) {
            messageId = String(intId)
        } else {
            throw DecodingError.dataCorruptedError(forKey: .message_id, in: container, debugDescription: "message_id must be String or Int")
        }
    }
}

struct RenderedContent: Codable {
    let rendered: String
}

解析使用示例

拿到API返回的Data后,用JSONDecoder正常解析即可:

let jsonData: Data = // 你的API返回数据
do {
    let messages = try JSONDecoder().decode([ChatMessage].self, from: jsonData)
    messages.forEach { msg in
        print("统一后的message_id: \(msg.messageId)")
    }
} catch {
    print("解析错误: \(error.localizedDescription)")
}

总结

通过Codable的自定义解析能力,我们可以在解析阶段就完成类型转换,完全不需要将转换器限制为单一预期类型。这两种方案都能稳定处理API返回的message_id类型不一致问题,等API修复后,只需要把模型里的messageId直接改为解析String类型即可,改动成本极低。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 12:31:02