【问题标题】:Optional URLs causing JSON decoding to fail in Swift 4在 Swift 4 中导致 JSON 解码失败的可选 URL
【发布时间】:2017-09-23 17:50:12
【问题描述】:

我正在试图弄清楚为什么使用可选 URL 会导致我的 JSON 解码在使用 Swift 4 时失败。我已经倾注了 WWDC “Whats new in Foundation”视频、Apples Playground 示例和一堆关于上网,但没有找到解决办法。

这是我为显示问题而创建的测试。说这是我的 json 数据:

let json = """
{
    "kind" : "",
    "total" : 2,
    "image_url" : "https://www.myawesomeimageURL.com/awesomeImage.jpg"
}
""".data(using: .utf8)!

这是我的结构:

    struct BusinessService: Decodable {
    let kind: String?
    let total: Int
    let image_url : URL?
}

这是我对其进行序列化的地方:

let myBusiness = try? JSONDecoder().decode(BusinessService.self, from: json)
print(myBusiness)

现在,问题是如果我收到缺少 image_url 的 json 数据,则 json 解码失败并给我 nil。

我很困惑为什么“种类”可以是一个可选的字符串,并且在它没有值时不会导致 json 解码失败,但是 image_url 不能是一个可选的 URL 而不会导致 json 失败。

我已经尝试了两天了,但没有运气。有没有人知道为什么这会失败?

我确实注意到了另一个难题,那就是 json 中的 image_url 实际上不必是有效的图像 URL。我可以输入任何字符串并且我的结构被序列化,所以我想我可能误解了它是如何工作的。我认为只有当它可以转换为有效的 URL 并且没有发生时,才会自动填充 URL。

对此的任何见解将不胜感激。

【问题讨论】:

    标签: swift ios11 json-deserialization swift4


    【解决方案1】:

    我们可以实施一个简单的调整来处理这种情况。您可以使用 try catch 块来解码 url 项。如果有Invalid URL Case,那么我们可以在try catch块中赋值为null。

        struct Example: Codable {
        let url: URL?
        
        private enum CodingKeys: String, CodingKey {
          case url
        }
        
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            do {
                url = try container.decode(URL.self, forKey: .url)
            }catch( _) {
                url = nil
            }
        }
    }
    

    注意:在 swift playground 中,上面的代码仍然会导致崩溃,但在常规 Xcode 项目中它只是按预期工作

    【讨论】:

      【解决方案2】:

      这对我来说符合预期。将image_url 设置为null 或完全忽略它会导致有效的BusinessService 被解码为nilimage_url 字段:

      struct Example: Decodable {
          let url: URL?
      }
      
      // URL is present. This works, obviously.
      try JSONDecoder().decode(Example.self, from: """
          { "url": "foo" }
          """.data(using: .utf8)!)
      
      // URL is missing, indicated by null. Also works.
      try JSONDecoder().decode(Example.self, from: """
          { "url": null }
          """.data(using: .utf8)!)
      
      // URL is missing, not even the key is present. Also works.
      try JSONDecoder().decode(Example.self, from: """
          {}
          """.data(using: .utf8)!) // works, too
      

      当我为字段提供无效的 URL 值(例如空字符串)时,唯一的问题就出现了。所以我想这是你的问题?

      // This throws: "Invalid URL string."
      try JSONDecoder().decode(Example.self, from: """
          { "url": "" }
          """.data(using: .utf8)!)
      

      您必须通过发送 null 或保留整行来为 URL 字段发送“无”值,而不是发送空字符串。

      我很困惑为什么“种类”可以是一个可选的字符串并且在它没有值时不会导致 json 解码失败,但是 image_url 不能是一个可选的 URL 而不会导致 json 失败。

      不同之处在于 JSON 中的 "" 是有效的 String 值,但不是有效的 URL。

      【讨论】:

      • 非常感谢您的解释。这让我整个周末都发疯了。我不太使用 JSON,所以我没有意识到 null 是一个有效值。遗憾的是,我使用的 API (Yelp) 传递的是 "" 而不是 null。我将不得不研究 json 容器(我认为)来解决这个问题。感谢您的帮助!
      • 乐于助人! “空”的情况总是有点棘手,因为很容易混淆空字符串和缺失字符串。 Swift 中的 Optional 类型使这一点变得更好,因为当字符串丢失时您会得到 .none,而当字符串存在但为空时会得到 .some("")。确实,为缺少的 URL 传递 "" 是一个糟糕的选择。
      猜你喜欢
      • 2018-06-28
      • 1970-01-01
      • 2019-01-11
      • 2021-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多