Swift 4如何正确解析JSON字符串为对象?嵌套属性访问异常
解决Swift中URLSession解析嵌套JSON的问题
嘿,我看你在解析嵌套JSON的时候遇到了麻烦,咱们来一步步搞定它!
首先得澄清一个点:你打印出来的那个带=的格式,其实是Swift字典的默认输出样式,不是JSON解析出错了——JSONSerialization已经正确把数据转成了字典,问题出在嵌套字典的访问方式上。
核心问题:强类型语言的类型转换要求
Swift是强类型语言,todo["published"]返回的是Any?类型,Swift不知道它到底是字典、数组还是其他类型,所以你不能直接用todo["published"]["date"]来访问嵌套属性。必须先把它向下转型成[String: Any]类型,才能访问里面的键值对。
修改你的解析代码
把原来访问published.date的部分改成这样:
do { guard let todo = try JSONSerialization.jsonObject(with: responseData, options: []) as? [String: Any] else { print("error trying to convert data to JSON") return } // 先把published转成字典,再提取date guard let publishedDict = todo["published"] as? [String: Any], let publishDate = publishedDict["date"] as? String else { print("Could not retrieve published date from JSON") return } print("Published date: \(publishDate)") // 原有的title访问逻辑可以保留 guard let todoTitle = todo["title"] as? String else { print("Could not get todo title from JSON") return } print("The title is: " + todoTitle) } catch { print("error trying to convert data to JSON") return }
更优雅的方案:用Codable做类型安全解析
手动转型不仅麻烦,还容易出错,推荐用Swift的Codable协议来做类型安全的JSON解析,代码会更简洁可靠。
1. 定义对应的数据模型
先创建和JSON结构匹配的结构体:
struct Todo: Codable { // 用CodingKey映射JSON下划线命名到Swift驼峰命名 let prettyArtists: String let published: Published let views: Int let ytId: String let playStart: Int let title: String let duration: Int let videoName: String let artists: String // 嵌套的published模型 struct Published: Codable { let date: String let now: Int let time: String let timestamp: Int } enum CodingKeys: String, CodingKey { case prettyArtists = "pretty_artists" case published, views case ytId = "yt_id" case playStart = "play_start" case title, duration case videoName = "video_name" case artists } }
2. 修改解析逻辑
用JSONDecoder替代JSONSerialization:
let task = session.dataTask(with: urlRequest) { (data, response, error) in guard error == nil else { print("error calling GET on /todos/1") print(error!) return } guard let responseData = data else { print("Error: did not receive data") return } do { // 直接解码成Todo对象 let todo = try JSONDecoder().decode(Todo.self, from: responseData) // 直接访问嵌套属性,类型完全安全 print("Published date: \(todo.published.date)") print("The title is: \(todo.title)") } catch { print("Error decoding JSON: \(error.localizedDescription)") return } } task.resume()
这样一来,你不仅能直接访问todo.published.date,编译时还能帮你检查属性名是否正确,避免了手动转型的各种坑。
内容的提问来源于stack exchange,提问作者M1X
相关产品推荐
相关产品推荐

