Swift 中的 JSON 解码。无法读取数据,因为它的格式不正确
Posted
技术标签:
【中文标题】Swift 中的 JSON 解码。无法读取数据,因为它的格式不正确【英文标题】:JSON decoding in Swift. The data couldn’t be read because it isn’t in the correct format 【发布时间】:2020-10-09 00:54:52 【问题描述】:我在解码 JSON 时遇到问题。它说:“无法读取数据,因为它的格式不正确。” 我不能指望它有什么问题。 你介意选一个吗?
端点:https://images-api.nasa.gov/search?q=apollo%2011&media_type=video
JSON 示例:
"collection":
"version": "1.0",
"href": "https://images-api.nasa.gov/search?q=apollo%2011&media_type=video",
"items": [
"href": "https://images-assets.nasa.gov/video/Apollo 11 Overview/collection.json",
"links": [
"href": "https://images-assets.nasa.gov/video/Apollo 11 Overview/Apollo 11 Overview~thumb.jpg",
"render": "image",
"rel": "preview"
,
"href": "https://images-assets.nasa.gov/video/Apollo 11 Overview/Apollo 11 Overview.srt",
"rel": "captions"
],
"data": [
"description": "Video highlights from the historic first manned landing on the moon, during the Apollo 11 mission in July 1969.",
"date_created": "2013-05-15T00:00:00Z",
"media_type": "video",
"keywords": [
"Apollo 11",
"Moon"
],
"nasa_id": "Apollo 11 Overview",
"center": "HQ",
"title": "Apollo 11 Overview"
]
,
我的模特:
struct NasaCollection: Codable
var collection: Collection
// MARK: - Collection
struct Collection: Codable
let version: String
let href: String
let items: [Item]
// MARK: - Item
struct Item: Codable
let href: String
let links: [ItemLink]
let data: Datum
// MARK: - ItemLink
struct ItemLink: Codable
let href: String
let render: Render?
// MARK: - Datum
struct Datum: Codable
let datumDescription: String
let dateCreated: Date
let keywords: [String]
let nasaID: String
let title: String
let location, description508, photographer, secondaryCreator: String?
let album: [String]?
enum Render: String, Codable
case image = "image"
// MARK: - CollectionLink
struct CollectionLink: Codable
let prompt, rel: String
let href: String
// MARK: - Metadata
struct Metadata: Codable
let totalHits: Int
enum CodingKeys: String, CodingKey
case totalHits = "total_hits"
决定:
func getVideos(completed: @escaping (Result<[Item], Error>)-> Void)
let endpoint = "https://images-api.nasa.gov/search?q=apollo%2011&media_type=video"
guard let url = URL(string: endpoint) else return
let task = URLSession.shared.dataTask(with: url) (data, response, error) in
if let _ = error
completed(.failure(error?.localizedDescription as! Error))
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else
completed(.failure(error?.localizedDescription as! Error))
return
guard let data = data else
completed(.failure(error?.localizedDescription as! Error))
return
do
let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .base64
let videos = try decoder.decode([Item].self, from: data)
completed(.success(videos))
catch
print(error.localizedDescription)
task.resume()
我认为我的模型是正确的,它“应该”被解码。我试图解码 JSON 的根,但仍然得到同样的错误。
【问题讨论】:
不要print(error.localizedDescription)
。只需print(error)
。您会收到更好的错误消息。
如果那真的是你的 JSON 那确实是无效的。
【参考方案1】:
首先您需要将data
类型从Datum
更改为数组[Datum]
,在Item
中,正如@emrcftci 在他的回答中提到的那样:
struct Item: Codable
let href: String
let links: [ItemLink]
let data: [Datum]
然后你需要将nasaID
属性更改为nasaId
和dateCreated
类型从Date
到String
,在Datum
:
struct Datum: Codable
let description: String
let dateCreated: String
let keywords: [String]
let nasaId: String
let title: String
let location, description508, photographer, secondaryCreator: String?
let album: [String]?
最后,当你解码时,将.convertFromSnakeCase
传递给JSONDecoder
的keyDecodingStrategy
属性,并在调用decode(_:from:)
函数时使用NasaCollection.self
作为类型,而不是[Item].self
:
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do
let decoded = try decoder.decode(NasaCollection.self, from: data)
print(decoded)
catch
print(error)
【讨论】:
【参考方案2】:Item
的data
应该是Datum
的数组 -> [Datum]
如你所见 ->
"collection":
"version": "1.0",
"href": "https://images-api.nasa.gov/search?q=apollo%2011&media_type=video",
"items": [
"href": "https://images-assets.nasa.gov/video/Apollo 11 Overview/collection.json",
"links": [
"href": "https://images-assets.nasa.gov/video/Apollo 11 Overview/Apollo 11 Overview~thumb.jpg",
"render": "image",
"rel": "preview"
,
"href": "https://images-assets.nasa.gov/video/Apollo 11 Overview/Apollo 11 Overview.srt",
"rel": "captions"
],
"data": [ // <------ Data has an array of an object(Datum).
"description": "Video highlights from the historic first manned landing on the moon, during the Apollo 11 mission in July 1969.",
"date_created": "2013-05-15T00:00:00Z",
"media_type": "video",
"keywords": [
"Apollo 11",
"Moon"
],
"nasa_id": "Apollo 11 Overview",
"center": "HQ",
"title": "Apollo 11 Overview"
]
,
您应该将data
设置为数组[Datum]
struct Item: Codable
let href: String
let links: [ItemLink]
let data: [Datum]
你应该更新Datum
对象如下
"description": "Video highlights from the historic first manned landing on the moon, during the Apollo 11 mission in July 1969.",
"date_created": "2013-05-15T00:00:00Z",
"media_type": "video",
"keywords": [
"Apollo 11",
"Moon"
],
"nasa_id": "Apollo 11 Overview",
"center": "HQ",
"title": "Apollo 11 Overview"
struct Datum: Codable
let description: String
let dateCreated: Date
let keywords: [String]
let nasaID: String
let title: String
let location, description508, photographer, secondaryCreator: String?
let album: [String]?
enum CodingKeys: String, CodingKey
case dateCreated = "date_created"
case nasaID = "nasa_id"
奖金
您正在尝试解析 NasaCollection
而不是 [Item]
。因为在 getVideos(completed:)
函数中,你的 do
块应该是这样的 ->
do
let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .base64
// You should try to decode `NasaCollection`!!!
let videos = try decoder.decode(NasaCollection.self, from: data)
completed(.success(videos))
【讨论】:
它说:“Swift.DecodingError.Context(codingPath: [], debugDescription: “期望解码 Array 但找到了一个字典。”,underlyingError: nil)) “它仍然没有'不解决问题... @EugeneBerezin 你能检查一下编辑后的答案吗?以上是关于Swift 中的 JSON 解码。无法读取数据,因为它的格式不正确的主要内容,如果未能解决你的问题,请参考以下文章
我如何使用解码器在swift 4中解析tableview中的json数组
将 JSON 数据从 Parse Cloud Code 返回到 Swift 中的可解码结构
无法在 Swift 中解析 JSON。 “应解码 Dictionary<String, Any>,但找到了一个数组。” [复制]