升级至Swift4后Decodable结构体解码失败,求解决方案
嘿,我太懂你从Swift 3切换到Swift 4+时,突然要上手Encodable/Decodable(也就是合起来的Codable协议)的那种纠结了——刚接触的时候确实容易在结构体定义上卡壳。不过别慌,我们对着你给出的JSON一步步来,轻松搞定解码用的结构体。
首先先明确你要解析的JSON结构(我把你给出的内容补全了部分,方便演示):
{
"status": "true",
"message": "Valid request",
"data": {
"user_id": "16",
"first_name": "Hamidouh",
"last_name": "Semix",
"other_name": null,
"fullname": "Hamidouh Semix",
"alias": null,
"about": "",
"sex_id": "1",
"sex": "Male",
"birth_date": "1989-08-15"
}
}
第一步:拆分JSON层级
这个JSON是两层嵌套结构:
- 顶层对象包含三个字段:
status、message、data data字段是一个嵌套的用户信息对象
第二步:定义对应的Swift结构体
我们需要分别定义顶层的响应结构体和嵌套的用户结构体,都遵循Codable协议(Swift会自动帮我们合成解码/编码所需的方法,不用手动写!)
方式一:直接匹配JSON的蛇形命名
如果不想额外处理字段命名,直接用JSON里的蛇形命名:
// 顶层响应结构体 struct APIResponse: Codable { let status: String let message: String let data: User } // 嵌套的用户信息结构体 struct User: Codable { let user_id: String let first_name: String let last_name: String let other_name: String? // 因为JSON里是null,所以用可选类型 let fullname: String let alias: String? // 同理,null对应可选类型 let about: String let sex_id: String let sex: String let birth_date: String // 如果之后要转Date,可以改成Date类型,后面会说 }
方式二:用Swift风格的驼峰命名(更推荐)
如果你习惯Swift的驼峰命名(比如userId代替user_id),可以通过JSONDecoder的keyDecodingStrategy自动转换,不用手动写CodingKeys:
struct APIResponse: Codable { let status: String let message: String let data: User } struct User: Codable { let userId: String let firstName: String let lastName: String let otherName: String? let fullname: String let alias: String? let about: String let sexId: String let sex: String let birthDate: String }
第三步:执行解码操作
不管用哪种命名方式,解码的逻辑都很简单,这里以驼峰命名的版本为例:
// 假设你已经获取到JSON数据(比如从网络请求得到的Data) let jsonData: Data = ... do { let decoder = JSONDecoder() // 开启蛇形转驼峰的自动映射 decoder.keyDecodingStrategy = .convertFromSnakeCase let response = try decoder.decode(APIResponse.self, from: jsonData) // 解码成功后就可以直接用数据了 print("用户ID:\(response.data.userId)") print("用户全名:\(response.data.fullname)") } catch { print("解码失败:\(error.localizedDescription)") }
几个关键细节要注意
status是String不是Bool:你的JSON里status的值是字符串"true",不是布尔值true,所以结构体里必须定义为String类型,不然解码会直接失败!- 可选类型的使用:JSON里值为
null的字段(比如other_name、alias),一定要定义为可选类型(String?),否则解码时遇到null会抛出错误。 - 日期转换(可选):如果想把
birth_date直接转成Swift的Date类型,可以修改User结构体的字段,并给解码器设置日期解析策略:
注意:如果你的日期格式不是标准ISO8601,可能需要自定义日期解析器。// 修改User结构体的birthDate字段 let birthDate: Date // 解码时添加日期策略 decoder.dateDecodingStrategy = .iso8601
这样你就能顺利把JSON数据转换成Swift对象了,是不是比想象中简单?
内容的提问来源于stack exchange,提问作者Sanford Smithers

