【问题标题】:Type Mismatch error parsing JSON with Swift Decodable使用 Swift Decodable 解析 JSON 的类型不匹配错误
【发布时间】:2018-08-23 16:42:16
【问题描述】:

当我尝试解码 JSON 时出现错误:

(错误:typeMismatch(Swift.String,Swift.DecodingError.Context(codingPath:[sweetyanime.Video.(_D1045E05CDE474AEBA8BDCAF57455DC3 中的 CodingKeys).video,sweetyanim.iD.(_D1045E05CDE474AEBA8BDCAF57455DC3 中的 CodingKeys).ID,sweetyyanime.other.( CodingKeys in _D1045E05CDE474AEBA8BDCAF57455DC3).CountOfVideos], debugDescription: "期望解码字符串,但找到了字典。", 底层错误: 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) 斯威夫特代码:

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
}

【问题讨论】:

    标签: json swift decodable


    【解决方案1】:

    让我们在错误消息中添加一些换行符以使其易于理解:

    (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”的值。它需要一个字符串,但它找到了一个字典。

    您需要定义一个与“CountOfVideos”字典对应的struct(它似乎包含一个键,“1Series”,带有一个字符串值),或者您需要从您的@ 中删除CountOfVideos 属性987654324@ struct 所以你根本不会尝试解码它。

    【讨论】:

      【解决方案2】:

      我认为您应该实现作为可解码的一部分的 init(来自解码器)初始化程序。它在如何处理嵌套 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 中的某些内容,因此请修改/采纳想法并根据需要重写)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-06-09
        • 1970-01-01
        • 2021-02-22
        • 1970-01-01
        • 2018-10-21
        • 1970-01-01
        相关资源
        最近更新 更多