我在解析 reddit 的 JSON 时遇到一个小问题。
简化的 reddit JSON 响应:
{
"kind": "Listing",
"data": {
"after": "t3_c2wztu",
"before": null,
"children": [
{
"data": {
"all_awardings": [],
"approved_at_utc": null,
"approved_by": null
},
"kind": "t3"
}
],
"dist": 25,
"modhash": ""
}
}
我简化了 JSON,因为它可以达到 4000 行长,大部分是重复的子对象。
当我们查看“children”对象中的第二个“data”键时,我们就获得了所有需要的数据,例如图像、用户名等。
我在 Swift 中的结构如下:看到 JSON 是嵌套的,我相信我需要创建嵌套结构或多个结构来帮助深入了解 JSON。我这样说对吗?
struct Model: Decodable {
let data : Children?
enum CodingKeys: String, CodingKey {
case data = "data"
}
}
struct Children: Decodable {
let data: [Child]?
enum CodingKeys: String, CodingKey {
case data = "data"
}
}
//MARK - there is MORE than author and full name, we are just doing this for ease of parsing.
struct Child: Decodable {
let author : String?
let authorFullname : String?
enum CodingKeys: String, CodingKey {
case author = "author"
case authorFullname = "author_fullname"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
author = try values.decodeIfPresent(String.self, forKey: .author)
authorFullname = try values.decodeIfPresent(String.self, forKey: .authorFullname)
}
}
现在这是我的 URLSession 调用:
class NetworkManager {
static var shared: NetworkManager = { return NetworkManager() }()
private init(){}
public func getFrontPage(completion: @escaping (Model?) -> Void) {
guard let url = URL(string: "https://www.reddit.com/r/all/.json") else { fatalError("Invalid URL") }
URLSession.shared.dataTask(with: url) { data, response, err in
if(err != nil) {
completion(nil)
}
guard let httpResponse = response as? HTTPURLResponse else { fatalError("URL Response Error") }
switch httpResponse.statusCode {
case 200:
if let data = data {
do {
let data = try JSONDecoder().decode(Model.self, from: data)
completion(data)
} catch {
print("ERROR DECODING JSON \(err.debugDescription)")
}
}
break
default:
completion(nil)
break
}
}.resume()
}
最后在 ViewDidLoad 中:
var redditData = [Model]()
override func viewDidLoad() {
super.viewDidLoad()
NetworkManager.shared.getFrontPage { (items) in
// self.redditData = items?.data
print(items)
DispatchQueue.main.async {
// update the UI
}
}
}
这是我当前无法克服的错误:
self.redditData = items?.data 给我一个错误:
Cannot assign value of type 'Children?' to type '[Model]'
问题: 1.我的结构布局正确吗?不用担心实际数据,例如用户名等,我在这篇文章中缩短了它。
我是否在网络管理器功能中正确“深入”了 JSON?
如何修复 viewController 类中的错误?
抱歉这个话题太长了!!
最佳答案
您的类型有点困惑。
getFrontPage
的完成类型是 (Model?) -> Void
那么让我们看看你在哪里使用它。
NetworkManager.shared.getFrontPage { (items) in
// items is Model? so...
// items?.data is of type Children?
// BUT self.redditData is of type [Model]
// self.redditData = items?.data
print(items)
DispatchQueue.main.async {
// update the UI
}
}
您显示的模型结构与示例 JSON 不匹配。这是一些可以工作的结构。我不熟悉 Reddit API,所以这些可能需要调整。
struct Model : Decodable {
let kind: String
let data: ListingData
}
struct ListingData: Decodable {
let after: String
let before: String?
let children: [Child]
let dist: Int
let modhash: String
}
struct ChildData : Decodable {
let allAwardings: [String]
let approvedAtUtc: String?
let approvedBy: String?
}
struct Child: Decodable {
let data: ChildData
let kind: String?
}
如果您在 JSONDecoder
上使用 .convertFromSnakeCase
,则可以避免所有 CodingKey
内容。只需将 getFrontPage
更改为如下解码:
let decoder = try JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let model = try decoder.decode(Model.self, from: data)
completion(model)
现在,只需确保 self.redditData 的类型与您感兴趣的模型上的字段匹配即可!
var self.redditData = [Child]()
NetworkManager.shared.getFrontPage { (model) in
self.redditData = model?.data.children ?? []
print(items)
DispatchQueue.main.async {
// update the UI
}
}
希望这有帮助!
关于json - 使用 Swift Codable 解析 Reddit JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56710386/