重写UnkeyedDecodingContainer协议方法未被调用,如何解决?
解码自定义Money类型时UnkeyedDecodingContainer扩展方法不被调用的问题
已正常工作的KeyedDecodingContainer扩展
以下扩展KeyedDecodingContainer的代码可以正常将JSON字符串解码为Money类型:
extension KeyedDecodingContainer { func decode(_: Money.Type, forKey key: Key) throws -> Money { let str = try decode(String.self, forKey: key) return try str.toMoney(on: key) } func decodeIfPresent(_: Money.Type, forKey key: Key) throws -> Money? { let str = try decodeIfPresent(String.self, forKey: key) return try str?.toMoney(on: key) } }
无法生效的UnkeyedDecodingContainer扩展
为了解码[Money]数组,我尝试对UnkeyedDecodingContainer做类似扩展,但这些重写的方法从未被调用:
extension UnkeyedDecodingContainer { mutating func decode(_: Money.Type) throws -> Money { let str = try decode(String.self) return try str.toMoney() } mutating func decodeIfPresent(_: Money.Type) throws -> Money? { let str = try decodeIfPresent(String.self) return try str?.toMoney() } }
问题分析与限制
- 我推测问题核心在于
KeyedDecodingContainer是结构体,而UnkeyedDecodingContainer是协议,导致扩展方法无法被正确分发调用。 - 标准做法是扩展
Money实现自定义Decodable的init(from:),但我无法这么做:Money已经遵循Decodable协议,且已有默认实现(期望从Double而非String解码),无法重写该方法。
最小可复现代码
Money是第三方库类型的别名:
typealias Money = Dollars<Double>
String的扩展方法,用于将字符串转为Money:
extension String { func toMoney(on key: CodingKey? = nil) throws -> Money { if let money = Money(self) { return money } throw DecodingError.dataCorrupted(.init( codingPath: key.map { [$0] } ?? [], debugDescription: "Can't convert JSON String to Money" )) } }
使用示例
struct PriceData: Decodable { let price: Money? let prices: [Money] } // 注意:JSON中的值是字符串类型 let jsonData = """ { "price": "10.5", "prices": ["5.3", "7.1", "9.6"] } """.data(using: .utf8)! do { let coin = try JSONDecoder().decode(PriceData.self, from: jsonData) print("Price: ", coin.price) print("Prices: ", coin.prices) } catch { print("Error decoding JSON: \(error)") }
内容的提问来源于stack exchange,提问作者Roman
相关产品推荐
相关产品推荐

