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
相关产品推荐
相关产品推荐

