You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:40:25