使用Swift Codable解析Reddit JSON
我在从reddit解析JSON时遇到了一个小问题 简化的reddit JSON响应:使用Swift Codable解析Reddit JSON,json,swift,Json,Swift,我在从reddit解析JSON时遇到了一个小问题 简化的reddit JSON响应: { "kind": "Listing", "data": { "after": "t3_c2wztu", "before": null, "children": [ { "data": { "all_awardings": [],
{
"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.我的结构布局正确吗?不要担心实际数据,比如用户名等等,我在这篇文章中缩短了它
抱歉,这么长的话题 你只是把你的类型弄混了一点
getFrontPage
的完成类型是(型号?->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不匹配。这里有一些结构可以工作。我不熟悉RedditAPI,因此可能需要对其进行调整
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
}
}
希望这有帮助 我知道我的孩子数据有点不可靠,在我需要它的地方是正确的,但我没有修复它在这里的外观…但是,这比我拥有的要干净得多!非常感谢!但它解决了你的主要问题吗?self.redditData?????completion(data)的赋值引发以下问题:无法将“data”类型的值转换为预期的参数类型“Model?”,让data=try JSONDecoder().decode(Model.self,from:data)JSONDecoder().keyDecodingStrategy=.convertFromSnakeCase completion(data)。这得到了我的JSON响应!哎呀!我明白问题所在。我会修好的。