使用Swift Decodable解码含转义字符与花括号的JSON字符串失败问题求助
解决Swift Decodable解码嵌套转义JSON字符串的问题
首先,咱们先找出你解码失败的根本原因:你在Swift中定义的JSON字符串写法有误,导致生成的JSON本身格式无效,这才是返回nil的核心问题。
问题分析
你用三重引号"""定义多行字符串时,错误地使用了\"来表示JSON里的转义双引号。但在Swift的多行字符串中,\"会被直接解析成一个普通双引号,而非JSON要求的转义双引号\"(也就是JSON字符串里的\+")。最终生成的JSON会变成这样的无效格式:
{ "orders":[ { "extra":"{"desired_pick_up_time":"ASAP"}" // 这里的双引号未转义,破坏了JSON结构 } ] }
自然无法被正确解码。
解决方案1:修正JSON字符串,将extra解码为String
先把Swift中的JSON字符串写对:要在JSON里表示转义双引号,需要在Swift多行字符串中写\\"(第一个\是Swift的转义符,用来表示第二个\是JSON的转义符)。
正确的JSON字符串定义:
var json = """ { "orders":[ { "extra":"{\\"desired_pick_up_time\\":\\"ASAP\\"}" } ] } """
或者用普通字符串写法:
var json = "{\"orders\":[{\"extra\":\"{\\\"desired_pick_up_time\\\":\\\"ASAP\\\"}\"}]}"
此时你原来的模型代码完全可以正常工作,建议修正解码代码中的try?(它会吞掉错误,不利于排查问题):
let jsonData = json.data(using: .utf8)! let decoder = JSONDecoder() do { let welcome = try decoder.decode(Welcome.self, from: jsonData) print(welcome) // 现在能正常输出解码结果了 } catch { print("解码错误:\(error)") }
解决方案2:直接将extra解码为结构体(进阶需求)
如果你的目标不是拿到String,而是要解析extra里的desired_pick_up_time值,可以自定义解码逻辑,直接把嵌套的JSON字符串解码为对应模型:
- 定义
Extra结构体:
struct Extra: Decodable { let desiredPickUpTime: String enum CodingKeys: String, CodingKey { case desiredPickUpTime = "desired_pick_up_time" } }
- 修改
Order结构体,自定义解码逻辑:
struct Order: Decodable { let extra: Extra init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 第一步:把extra字段解码为String let extraString = try container.decode(String.self, forKey: .extra) // 第二步:把String转为Data,再解码为Extra guard let extraData = extraString.data(using: .utf8) else { throw DecodingError.dataCorruptedError( forKey: .extra, in: container, debugDescription: "无法将extra字符串转为Data" ) } let innerDecoder = JSONDecoder() self.extra = try innerDecoder.decode(Extra.self, from: extraData) } enum CodingKeys: String, CodingKey { case extra } }
- 解码测试:
let jsonData = json.data(using: .utf8)! let decoder = JSONDecoder() do { let welcome = try decoder.decode(Welcome.self, from: jsonData) print(welcome.orders.first?.extra.desiredPickUpTime) // 直接输出"ASAP" } catch { print("解码错误:\(error)") }
内容的提问来源于stack exchange,提问作者Blisko
相关产品推荐
相关产品推荐

