使用 Swift 读取 JSON 文件
在本文中,我们将通过一些示例,了解如何使用 JSONSerialization 和 JSONDecoder 类读取 JSON 文件。如今,大多数 iOS 应用程序都使用这些类来处理 JSON 文件。
您可以使用 JSONSerialization 类在 Swift 语言中读取 JSON 文件。要读取 JSON 文件,首先需要将其转换为字符串或数据对象。然后,您可以将字符串或数据对象传递给 JSONSerialization 类,以将其转换为字典或数组对象。
JSONSerialization
iOS 和 macOS 的 Foundation 框架默认包含一个 JSONSerialization 类。要创建 Swift 字典或数组,此类需要一个字符串或数据对象。使用同一个类,您还可以将字典或数组转换为 JSON 对象。序列化和反序列化过程由 JSONSerialization 类处理。
该类的主要函数 jsonObject(with:options:) 用于反序列化 JSON 数据,即将 JSON 数据转换为 Swift 对象。此方法需要一个包含 JSON 数据的数据对象以及一个名为 options 的参数,该参数用于控制方法的行为。此方法返回一个 Swift 对象,该对象可以是数组或字典。JSON 数据格式将决定返回类型。
以下是如何读取 JSON 文件并将其解析为字典的示例 -
使用 JSONSerialization 类读取 JSON
以下是 JSON 示例 -
示例
{
"id": 1,
"title": "iPhone 12",
"price": 749,
"thumbnail": "https://i.dummyjson.com/data/products/1/thumbnail.jpg",
"manufacturedDetail": {
"company": {
"manufacturedBy": "Apple Inc."
}
}
}
我们将使用上面的 JSON 格式进行读取。您可以向 Xcode 项目添加一个扩展名为".json"的新文件,并为其指定任意名称。
读取 JSON 文件
func readJSONFile(forName name: String) {
do {
if let bundlePath = Bundle.main.path(forResource: name, ofType: "json"),
let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) {
if let json = try JSONSerialization.jsonObject(with: jsonData, options: .mutableLeaves) as? [String: Any] {
print("JSON: \(json)")
} else {
print("Given JSON is not a valid dictionary object.")
}
}
} catch {
print(error)
}
}
输出
JSON: ["title": iPhone 12, "price": 749, "thumbnail": https://i.dummyjson.com/data/products/1/thumbnail.jpg, "id": 1, "manufacturedDetail": {
company = {
manufacturedBy = "Apple Inc.";
};
}]
这将返回一个 JSON 对象,您可以在代码中将其用作字典。如果您的 JSON 文件是一个对象数组,则可以使用 mutableContainers 选项代替 mutableLeaves 选项。由于我们需要从 JSON 对象中读取字典,因此我们将使用 mutableLeaves 选项。
使用 JSONDecoder() 类读取 JSON
新版本的 Swift 引入了 Codable 协议,这使得使用起来更加简单灵活。
然后使用 JSONDecoder 类将文件中的 JSON 数据解析为给定类型的实例(可以是类或结构体)。decode(_:from:) 方法用于反序列化 JSON 数据,并返回生成的 Type 对象以访问该 Type 对象的属性。
我们尝试使用 Codable 协议读取上面给出的相同 JSON 示例。在我们准备使用 JSONDecoder() 类解码 JSON 数据之前,让我们先准备一下解码时要提供的模型类。
以下是根据上述 JSON 数据构建的模型类 -
import Foundation
struct Product: Decodable {
let id: Int
let title: String
let price: Int
let thumbnail: String
let manufacturedBy: String
enum RootKeys: String, CodingKey {
case id, title, price, thumbnail, manufacturedDetail
}
enum ManufacturedKeys: String, CodingKey {
case company
}
enum CompanyKeys: String, CodingKey {
case manufacturedBy
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: RootKeys.self)
id = try values.decode(Int.self, forKey: .id)
title = try values.decode(String.self, forKey: .title)
price = try values.decode(Int.self, forKey: .price)
thumbnail = try values.decode(String.self, forKey: .thumbnail)
let manufacturedContainer = try values.nestedContainer(keyedBy: ManufacturedKeys.self, forKey: .manufacturedDetail)
let companyContainer = try manufacturedContainer.nestedContainer(keyedBy: CompanyKeys.self, forKey: .company)
self.manufacturedBy = try companyContainer.decode(String.self, forKey: .manufacturedBy)
}
}
如何解码?
func readJSONFile(forName name: String) {
do {
// 从主包创建路径并从路径获取数据对象
if let bundlePath = Bundle.main.path(forResource: name, ofType: "json"),
let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) {
// 使用 JSONDecoder() 类从 JSON 数据解码产品类型。
let product = try JSONDecoder().decode(Product.self, from: jsonData)
print("Product name: \(product.title) and its price: \(product.price)")
}
} catch {
print(error)
}
}
输出
Product name: iPhone 12 and its price: 749
结论
在 Swift 中,您可以通过底层 API 将原始 JSON 数据转换为数组或字典等集合。您可以使用 JSONSerialization 类将原始 JSON 对象转换为有意义的对象。该类内置于 Foundation 框架中。您可以在任何平台上使用此类,例如 iOS、macOS、watchOS 等。此外,您还可以反向使用反序列化过程将自定义对象转换回原始 JSON 数据。
在 Swift 4 中,Apple 引入了 Codable 协议,简化了序列化和反序列化过程。该协议提供了一种灵活的方式来解析 JSON 数据并将其存储到模型类/结构体中。使用该协议可以轻松地将模型对象转换为 JSON 数据。
Codable 协议有助于减少代码量并处理序列化和反序列化过程,使代码更简洁、更易于维护。

