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 对象包含正确解码的项目数组或错误。