swift - 解码来自 Reddit API 的 JSON 响应(post 评论)
swift - Decoding JSON response (post comments) from Reddit API
我在 JSON 中收到来自 Reddit API 的 reddit post 评论(来自特定 subreddit 的 post),然后通过 Structs 解析 JSON。当我尝试输出解码后的注释时出现错误:
Error decoding Json comments - typeMismatch(Swift.Dictionary<Swift.String, Any>,
Swift.DecodingError.Context(codingPath: [], debugDescription:
"Expected to decode Dictionary<String, Any> but found an array
instead.", underlyingError: nil))
也许我在我的结构中遗漏了一些东西,或者在 Repository getComments 方法中有不匹配的类型。请指教
enum RequestURL {
case top(sub: String, limit: Int)
case postAt(sub: String, id: String)
var url: String {
switch self {
case .top(let sub, let limit):
return "https://www.reddit.com/r/\(sub)/top.json?limit=\(limit)"
case .postAt(let sub, let id):
return "https://www.reddit.com/r/\(sub)/comments/\(id).json"
}
}
}
class HTTPRequester {
init() {}
func getData (url: RequestURL, completion: @escaping(Data?) -> Void) {
guard let url = URL(string: url.url) else {
print("Error: Request URL is nil!")
completion(nil)
return
}
URLSession.shared.dataTask(with: url) {data,_,error in
guard let jsonData = data else {
print(error ?? "Error")
completion(nil)
return
}
completion(jsonData)
}.resume()
}
}
class Service {
init() {}
func decodeJSONComments(url: RequestURL, completion: (@escaping (_ data: CommentListing?) -> Void)) {
HTTPRequester().getData(url: url) { jsonData in
do {
let postsResponse = try JSONDecoder().decode(CommentListing.self, from: jsonData!)
print(postsResponse)
completion(postsResponse)
} catch {
print("Error decoding Json comments - \(error)")
completion(nil)
}
}
}
}
class Repository {
init() {}
func getComments(sub: String, postId: String, completion: (@escaping ([RedditComment]) -> Void)) {
Service().decodeJSONComments(url: RequestURL.postAt(sub: sub, id: postId)) { (comments: CommentListing?) in
var commentsList = [CommentData]()
commentsList = (comments?.data.children) ?? []
let mappedComs = commentsList.map { (comment) -> RedditComment in
return RedditComment(
id: comment.data.id,
author: comment.data.author,
score: comment.data.score,
body: comment.data.body)
}
completion(mappedComs)
}
}
}
class UseCase {
func createComments(sub: String, postId: String, completion: (@escaping (_ data: [RedditComment]) -> Void)) {
Repository().getComments(sub: sub, postId: postId) { (comments: [RedditComment]) in
completion(comments)
}
}
}
UseCase().createComments(sub: "ios", postId: "4s4adt") { comments in
print(comments)
}
JSON结构
尝试将您的响应解码为 CommentListing
的数组,例如:
do {
let postsResponse = try JSONDecoder().decode([CommentListing].self, from: jsonData!)
print(postsResponse)
completion(postsResponse)
} catch {
print("Error decoding Json comments - \(error)")
completion(nil)
}
您提到您有以下错误:
typeMismatch(Swift.Dictionary<String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))
让我们解构一下:
您可以从中读到两点有用的信息:
首先,debugDescription
:本应解码 Dictionary 但发现了一个数组。
这意味着您正在尝试解码字典,但 JSON 包含一个数组。请注意,您标记为 Codable 的大多数普通类型都将编码为字典。
其次,codingPath
,在你的例子中是一个空数组([]
),这意味着这个问题就在你试图解码的根类型上。
现在让我们看看您发布的 Postman 回复。就在第 1 行,您可以看到最外面的容器(第 1 行)是一个数组。
但是当你解码的时候,你解码的是CommentListing
,它使用了键控容器(字典)。
所以要解决这个问题,你必须解码 CommentListing
s 的数组。
let postsResponse = try JSONDecoder().decode([CommentListing].self, from: jsonData!)
我在 JSON 中收到来自 Reddit API 的 reddit post 评论(来自特定 subreddit 的 post),然后通过 Structs 解析 JSON。当我尝试输出解码后的注释时出现错误:
Error decoding Json comments - typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))
也许我在我的结构中遗漏了一些东西,或者在 Repository getComments 方法中有不匹配的类型。请指教
enum RequestURL {
case top(sub: String, limit: Int)
case postAt(sub: String, id: String)
var url: String {
switch self {
case .top(let sub, let limit):
return "https://www.reddit.com/r/\(sub)/top.json?limit=\(limit)"
case .postAt(let sub, let id):
return "https://www.reddit.com/r/\(sub)/comments/\(id).json"
}
}
}
class HTTPRequester {
init() {}
func getData (url: RequestURL, completion: @escaping(Data?) -> Void) {
guard let url = URL(string: url.url) else {
print("Error: Request URL is nil!")
completion(nil)
return
}
URLSession.shared.dataTask(with: url) {data,_,error in
guard let jsonData = data else {
print(error ?? "Error")
completion(nil)
return
}
completion(jsonData)
}.resume()
}
}
class Service {
init() {}
func decodeJSONComments(url: RequestURL, completion: (@escaping (_ data: CommentListing?) -> Void)) {
HTTPRequester().getData(url: url) { jsonData in
do {
let postsResponse = try JSONDecoder().decode(CommentListing.self, from: jsonData!)
print(postsResponse)
completion(postsResponse)
} catch {
print("Error decoding Json comments - \(error)")
completion(nil)
}
}
}
}
class Repository {
init() {}
func getComments(sub: String, postId: String, completion: (@escaping ([RedditComment]) -> Void)) {
Service().decodeJSONComments(url: RequestURL.postAt(sub: sub, id: postId)) { (comments: CommentListing?) in
var commentsList = [CommentData]()
commentsList = (comments?.data.children) ?? []
let mappedComs = commentsList.map { (comment) -> RedditComment in
return RedditComment(
id: comment.data.id,
author: comment.data.author,
score: comment.data.score,
body: comment.data.body)
}
completion(mappedComs)
}
}
}
class UseCase {
func createComments(sub: String, postId: String, completion: (@escaping (_ data: [RedditComment]) -> Void)) {
Repository().getComments(sub: sub, postId: postId) { (comments: [RedditComment]) in
completion(comments)
}
}
}
UseCase().createComments(sub: "ios", postId: "4s4adt") { comments in
print(comments)
}
JSON结构
尝试将您的响应解码为 CommentListing
的数组,例如:
do {
let postsResponse = try JSONDecoder().decode([CommentListing].self, from: jsonData!)
print(postsResponse)
completion(postsResponse)
} catch {
print("Error decoding Json comments - \(error)")
completion(nil)
}
您提到您有以下错误:
typeMismatch(Swift.Dictionary<String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))
让我们解构一下:
您可以从中读到两点有用的信息:
首先,debugDescription
:本应解码 Dictionary
这意味着您正在尝试解码字典,但 JSON 包含一个数组。请注意,您标记为 Codable 的大多数普通类型都将编码为字典。
其次,codingPath
,在你的例子中是一个空数组([]
),这意味着这个问题就在你试图解码的根类型上。
现在让我们看看您发布的 Postman 回复。就在第 1 行,您可以看到最外面的容器(第 1 行)是一个数组。
但是当你解码的时候,你解码的是CommentListing
,它使用了键控容器(字典)。
所以要解决这个问题,你必须解码 CommentListing
s 的数组。
let postsResponse = try JSONDecoder().decode([CommentListing].self, from: jsonData!)