如果单个元素解码失败,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 {
// 从主包创建路径并从路径获取数据对象
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"的视图控制器以及一个方法。在此方法中,我们从主包中读取本地 JSON 文件。之后,我们使用 JSONDecoder().decode() 方法解码 JSON 数据。我们将类型"[Actor].self"传递给解码方法,如果成功解码,该方法将返回一个 Actor 对象数组。
在此示例中,json 变量包含一个包含两个对象的数组,其中第二个对象无效(缺少必需属性)。JSONDecoder 用于解码每个对象,并捕获解码过程中发生的任何错误并将其打印到控制台。成功解码的对象将添加到名为 actors 的数组中。该示例的输出结果为:-
keyNotFound(CodingKeys(stringValue: "topMovie", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 1", intValue: 1)], debugDescription: "没有与键 CodingKeys(stringValue: "topMovie", intValue: nil) ("topMovie") 关联的值。", understandingError: 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 实例的 decoder(:from:completionHandler:) 方法,并向其传递一个接受 Result 对象作为参数的闭包,来应用自定义解码方法。Result 对象中可能包含正确解码的元素数组或错误信息。