Swift JSONDecode 解码数组在单个元素解码失败时也会失败


在 Swift 中,使用 JSONDecoder 类处理 JSON 对象非常容易。始终需要使用 Codable 协议创建模型类或结构体。一个小的错误会导致无法解码整个 JSON 对象。让我们探索一些示例,以了解何时可能发生此错误以及如何在 Swift 中处理它。

什么是 JSONDecoder 类?

然后使用 JSONDecoder 类将 JSON 数据从文件解析为给定类型的实例,可以是类或结构体。decode(_:from:) 方法用于反序列化 JSON 数据,然后返回生成的 Type 对象以访问 Type 对象的属性。

我们尝试使用 Codable 协议读取上面给出的相同 JSON 作为示例。在准备好使用 JSONDecoder() 类解码 JSON 数据之前,让我们准备在解码时提供的模型类。

这是一个创建此错误条件的示例

步骤 1 - 创建 JSON 文件

在此步骤中,我们将创建一个示例 JSON 并将其另存为 Xcode 项目中的“.json”文件。这是我们在此示例中将使用的 JSON:

[
   {
      "name": "Tom Cruise",
      "age": 56,
      "bornAt": "Syracuse, NY",
      "birthdate": "July 3, 1962",
      "photo": "https://jsonformatter.org/img/tom-cruise.jpg",
      "topMovie": "Mission Impossible"
   },
   {
      "name": "Robert Downey Jr.",
      "age": 53,
      "bornAt": "New York City, NY",
      "birthdate": "April 4, 1965",
      "photo": "https://jsonformatter.org/img/Robert-Downey-Jr.jpg"
   }
]

我们将此 JSON 文件命名为“sample.json”并保存在项目目录中。

步骤 2 - 创建模型结构

此步骤涉及创建名为“Actor”的结构体并符合 Decodable 协议。代码如下:

import Foundation
struct Actor: Decodable {
   let name: String
   let age: Int
   let bornAt: String
   let birthdate: String
   let photo: String
   let topMovie: String
}

步骤 3 - 将 JSON 解码为 Actor 结构体

在此步骤中,我们将解码 JSON 文件并将数据保存到 Actor 模型中。代码如下:

import UIKit
class CodableController: UIViewController {
       
   override func viewDidLoad() {
      super.viewDidLoad()
      decodeJSON()
   }
   func decodeJSON() {
      do {
         // creating path from the main bundle and getting data object from the path
         if let bundlePath = Bundle.main.path(forResource: "sample", ofType: "json"),
         let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) {
                         
            let actors = try JSONDecoder().decode([Actor].self, from: jsonData)
            print("Number of actors parsed: \(actors.count)")
         }
      } catch {
         print(error)
      }
   }
}

在上面的示例中,我们创建了一个名为“CodableController”的视图控制器以及一个方法。在此方法中,我们正在从主 bundle 读取本地 JSON 文件。之后,我们使用 JSONDecoder().decode() 方法解码 JSON 数据。我们将类型“[Actor].self”传递给 decode 方法,如果成功解码,则该方法将返回演员对象的数组。

在此示例中,json 变量包含两个对象的数组,其中第二个对象无效(缺少必需的属性)。JSONDecoder 用于解码每个对象,并且在解码过程中发生的任何错误都会被捕获并打印到控制台。成功解码的对象将添加到名为 actors 的数组中。示例的输出将是:

keyNotFound(CodingKeys(stringValue: "topMovie", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 1", intValue: 1)], debugDescription: "No value associated with key CodingKeys(stringValue: "topMovie", intValue: nil) ("topMovie").", underlyingError: nil))

如您所见,由于 JSON 数据中缺少值,解码过程失败。可以清楚地说,键“topMovie”的值丢失了。

步骤 4 - 修复错误

在此步骤中,我们将尝试修复上述错误。根据 JSON 文件,第二个对象缺少“topMovie”键。如果您认为此值不需要在应用程序中执行进一步的操作,则可以将其设为可选,如下所示:

import Foundation
struct Actor: Decodable {
   let name: String
   let age: Int
   let bornAt: String
   let birthdate: String
   let photo: String
   let topMovie: String?
}

现在,您可以再次运行代码,您将在控制台中看到打印的输出:

Number of actors parsed: 2

如您所见,解码过程已成功完成,没有错误。

结论

Swift 提供了 JSONDecoder 类来将 JSON 对象编码和解码为 Swift 的模型对象,反之亦然。我们有责任仔细处理属性声明,否则会导致错误。

对于 JSON 对象中缺少的值,可以将这些变量设为可选。鉴于这些值可能不会出现在服务器响应中,因此建议将它们设为可选。

另一种解决此问题的方法是使用另一种解码技术,该技术分别解码每个对象并丢弃任何解码错误。即使无法解码一个或多个元素,这也能使解码继续进行。

您可以通过调用 JSONDecoder 实例的 decode( :from:completionHandler:) 方法并向其传递一个接受 Result 对象作为参数的闭包来应用自定义解码方法。Result 对象包含正确解码的项目数组或错误。

更新于:2023年4月11日

215 次浏览

开启你的 职业生涯

通过完成课程获得认证

开始学习
广告