类型不匹配错误解析 JSON 与 Swift 可解码
Type Mismatch error parsing JSON with Swift Decodable
当我尝试解码 JSON 时出现错误:
(Error: typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [sweetyanime.Video.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).video, sweetyanime.iD.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).ID, sweetyanime.other.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).CountOfVideos], debugDescription: "Expected to decode String but found a dictionary instead.", underlyingError: nil)
1) JSON:
{ "video":{
"ID":{
"Name":"NameOfAnime",
"Describe":"SomeDescribe",
"Image":"https://firebasestorage.googleapis.com/v0/b/sweety-anime-e6bb4.appspot.com/o/main.png?alt=media&token=042a2dad-8519-4904-9ba3-262c2c962434",
"CountOfVideos":{
"1Series":"https://firebasestorage.googleapis.com/v0/b/sweety-anime-e6bb4.appspot.com/o/message_movies%252F12323439-9729-4941-BA07-2BAE970967C7.movalt=media&token=978d8b3a-7aad-468f-87d4-2b587d616720"
}
} } }
2)Swift代码:
let jsonUrl = "file:///Users/tima/WebstormProjects/untitled/db.json"
guard let url = URL(string: jsonUrl) else { return }
URLSession.shared.dataTask(with: url) { (data, reponse, error) in
guard let data = data else {return}
do {
let video = try
JSONDecoder().decode(Video.self, from: data)
print(video.video.ID.Name)
} catch let jsonErr {
print("Error: ", jsonErr)
}
}.resume()
3) Video.swift
struct Video: Decodable {
private enum CodingKeys : String, CodingKey { case video = "video"
}
let video: iD
}
struct iD: Decodable {
private enum CodingKeys : String, CodingKey { case ID = "ID" }
let ID: other
}
struct other: Decodable {
private enum CodingKeys : String, CodingKey {
case Name = "Name"
case Describe = "Describe"
case Image = "Image"
case CountOfVideos = "CountOfVideos"
}
let Name: String
let Describe: String
let Image: String
let CountOfVideos: String
}
让我们在您的错误消息中添加一些换行符以使其易于理解:
(Error: typeMismatch(Swift.String,
Swift.DecodingError.Context(codingPath: [
sweetyanime.Video.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).video,
sweetyanime.iD.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).ID,
sweetyanime.other.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).CountOfVideos],
debugDescription: "Expected to decode String but found a dictionary instead.",
underlyingError: nil)
所以它试图解码“CountOfVideos”的值。它需要一个字符串,但它找到了一个字典。
您需要定义一个 struct
对应于“CountOfVideos”字典(它似乎包含一个键,“1Series”,带有一个字符串值),或者您需要删除 CountOfVideos
属性 来自你的 other
结构,所以你根本不要尝试解码它。
我认为您应该实现作为 Decodable 一部分的 init(from decoder) 初始值设定项。与自动实现相比,它在如何处理嵌套 JSON 方面提供了更大的灵活性。一种可能的实现方式如下:
struct Video: Decodable {
let name: String
let describe: String
let image: String
let countOfVideos: String
private enum VideoKey: String, CodingKey {
case video = "video"
}
private enum IDKey: String, CodingKey {
case id = "ID"
}
private enum CodingKeys: String, CodingKey {
case name = "Name"
case describe = "Describe"
case image = "Image"
case countOfVideos = "CountOfVideos"
}
private enum VideoCountKey: String, CodingKey {
case videoCount = "1Series"
}
init(from decoder: Decoder) throws {
let videoContainer = try decoder.container(keyedBy: VideoKey.self)
let idContainer = try videoContainer.nestedContainer(keyedBy: IDKey.self, forKey: .video)
let valuesContainer = try idContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .id)
self.name = try valuesContainer.decode(String.self, forKey: .name)
self.describe = try valuesContainer.decode(String.self, forKey: .describe)
self.image = try valuesContainer.decode(String.self, forKey: .image)
let videoCountContainer = try valuesContainer.nestedContainer(keyedBy: VideoCountKey.self, forKey: .countOfVideos)
self.countOfVideos = try videoCountContainer.decode(String.self, forKey: .videoCount)
}
这适用于 Playground 中的示例数据。我真的不知道您是否想要 videoCount 的键或值。 (对我来说,这两个都不像视频计数。通常,您只需要为嵌套 JSON 的每个级别定义一个 CodingKey 枚举,然后您可以根据需要解码各个值。(注意,因为我已经只看到了你的一个数据示例,这可能会破坏你正在使用的 API 中的某些东西,所以 modify/take 想法并根据需要重写)
当我尝试解码 JSON 时出现错误:
(Error: typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [sweetyanime.Video.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).video, sweetyanime.iD.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).ID, sweetyanime.other.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).CountOfVideos], debugDescription: "Expected to decode String but found a dictionary instead.", underlyingError: nil)
1) JSON:
{ "video":{
"ID":{
"Name":"NameOfAnime",
"Describe":"SomeDescribe",
"Image":"https://firebasestorage.googleapis.com/v0/b/sweety-anime-e6bb4.appspot.com/o/main.png?alt=media&token=042a2dad-8519-4904-9ba3-262c2c962434",
"CountOfVideos":{
"1Series":"https://firebasestorage.googleapis.com/v0/b/sweety-anime-e6bb4.appspot.com/o/message_movies%252F12323439-9729-4941-BA07-2BAE970967C7.movalt=media&token=978d8b3a-7aad-468f-87d4-2b587d616720"
}
} } }
2)Swift代码:
let jsonUrl = "file:///Users/tima/WebstormProjects/untitled/db.json"
guard let url = URL(string: jsonUrl) else { return }
URLSession.shared.dataTask(with: url) { (data, reponse, error) in
guard let data = data else {return}
do {
let video = try
JSONDecoder().decode(Video.self, from: data)
print(video.video.ID.Name)
} catch let jsonErr {
print("Error: ", jsonErr)
}
}.resume()
3) Video.swift
struct Video: Decodable {
private enum CodingKeys : String, CodingKey { case video = "video"
}
let video: iD
}
struct iD: Decodable {
private enum CodingKeys : String, CodingKey { case ID = "ID" }
let ID: other
}
struct other: Decodable {
private enum CodingKeys : String, CodingKey {
case Name = "Name"
case Describe = "Describe"
case Image = "Image"
case CountOfVideos = "CountOfVideos"
}
let Name: String
let Describe: String
let Image: String
let CountOfVideos: String
}
让我们在您的错误消息中添加一些换行符以使其易于理解:
(Error: typeMismatch(Swift.String,
Swift.DecodingError.Context(codingPath: [
sweetyanime.Video.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).video,
sweetyanime.iD.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).ID,
sweetyanime.other.(CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).CountOfVideos],
debugDescription: "Expected to decode String but found a dictionary instead.",
underlyingError: nil)
所以它试图解码“CountOfVideos”的值。它需要一个字符串,但它找到了一个字典。
您需要定义一个 struct
对应于“CountOfVideos”字典(它似乎包含一个键,“1Series”,带有一个字符串值),或者您需要删除 CountOfVideos
属性 来自你的 other
结构,所以你根本不要尝试解码它。
我认为您应该实现作为 Decodable 一部分的 init(from decoder) 初始值设定项。与自动实现相比,它在如何处理嵌套 JSON 方面提供了更大的灵活性。一种可能的实现方式如下:
struct Video: Decodable {
let name: String
let describe: String
let image: String
let countOfVideos: String
private enum VideoKey: String, CodingKey {
case video = "video"
}
private enum IDKey: String, CodingKey {
case id = "ID"
}
private enum CodingKeys: String, CodingKey {
case name = "Name"
case describe = "Describe"
case image = "Image"
case countOfVideos = "CountOfVideos"
}
private enum VideoCountKey: String, CodingKey {
case videoCount = "1Series"
}
init(from decoder: Decoder) throws {
let videoContainer = try decoder.container(keyedBy: VideoKey.self)
let idContainer = try videoContainer.nestedContainer(keyedBy: IDKey.self, forKey: .video)
let valuesContainer = try idContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .id)
self.name = try valuesContainer.decode(String.self, forKey: .name)
self.describe = try valuesContainer.decode(String.self, forKey: .describe)
self.image = try valuesContainer.decode(String.self, forKey: .image)
let videoCountContainer = try valuesContainer.nestedContainer(keyedBy: VideoCountKey.self, forKey: .countOfVideos)
self.countOfVideos = try videoCountContainer.decode(String.self, forKey: .videoCount)
}
这适用于 Playground 中的示例数据。我真的不知道您是否想要 videoCount 的键或值。 (对我来说,这两个都不像视频计数。通常,您只需要为嵌套 JSON 的每个级别定义一个 CodingKey 枚举,然后您可以根据需要解码各个值。(注意,因为我已经只看到了你的一个数据示例,这可能会破坏你正在使用的 API 中的某些东西,所以 modify/take 想法并根据需要重写)