非原创,Gemini 问答生成

Swift 中的 Codable 协议详解

Codable 协议是 Swift 4.0 中引入的一项新功能,它提供了一种简洁、类型安全的方式来将 Swift 类型的结构体、枚举和类编码为 JSON 数据,或从 JSON 数据解码为 Swift 类型。

Codable 协议实际上是 EncodableDecodable 两个协议的组合。Encodable 协议定义了如何将 Swift 类型编码为 JSON 数据,而 Decodable 协议定义了如何从 JSON 数据解码为 Swift 类型。

采用 Codable 协议的优势

采用 Codable 协议有以下几个优势:

  • 简洁: Codable 协议提供了简洁的语法来编码和解码数据,无需编写繁琐的代码。
  • 类型安全: Codable 协议可以确保编码和解码过程的类型安全性,防止出现类型转换错误。
  • 可扩展性: Codable 协议支持自定义编码器和解码器,可以满足更复杂的编码和解码需求。

采用 Codable 协议的步骤

要使 Swift 类型符合 Codable 协议,只需在类型定义后面添加 Codable 关键字即可。例如:

Swift

struct Person: Codable {
    let name: String
    let age: Int
}

在上面的代码中,Person 结构体符合 Codable 协议,这意味着它可以被编码为 JSON 数据,也可以从 JSON 数据解码。

编码和解码数据

要编码 Swift 类型为 JSON 数据,可以使用 JSONEncoder 类。例如:

Swift

let person = Person(name: "John Doe", age: 30)
let encoder = JSONEncoder()
do {
    let jsonData = try encoder.encode(person)
    print(String(data: jsonData, encoding: .utf8)!)
} catch {
    print("Error encoding person: \(error)")
}

上面的代码将 Person 实例编码为 JSON 数据并打印到控制台。

要从 JSON 数据解码 Swift 类型,可以使用 JSONDecoder 类。例如:

Swift

let jsonData = Data("""
{
  "name": "Jane Doe",
  "age": 25
}
""".utf8)
let decoder = JSONDecoder()
do {
    let person = try decoder.decode(Person.self, from: jsonData)
    print(person)
} catch {
    print("Error decoding JSON data: \(error)")
}

上面的代码将 JSON 数据解码为 Person 实例并打印到控制台。

自定义编码器和解码器

在某些情况下,可能需要自定义编码器和解码器来满足更复杂的编码和解码需求。例如,如果要将日期编码为 JSON 数据,可以使用自定义的日期编码器。

要创建自定义编码器,需要创建一个遵循 Encoder 协议的类。Encoder 协议定义了如何将值编码为 JSON 数据的方法。例如:

Swift

struct DateEncoder: Encoder {
    func container<T>(for type: T) throws -> EncodingContainer<T> where T: Encodable {
        switch type {
        case Date.self:
            return .singleValue(DateContainer(encoder: self))
        default:
            return try encoder.container(for: type)
        }
    }

    func encode<T>(_ value: T) throws where T: Encodable {
        if let date = value as? Date {
            let container = try container(for: Date.self)
            try container.encode(date)
        } else {
            try encoder.encode(value)
        }
    }
}

struct DateContainer<Encoder>: EncodingContainer {
    private let encoder: Encoder

    init(encoder: Encoder) {
        self.encoder = encoder
    }

    func encode(_ value: Date) throws {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        let string = formatter.string(from: value)
        try encoder.encode(string)
    }
}

上面的代码创建了一个自定义的 DateEncoder 类,用于将日期编码为 JSON 字符串。

要使用自定义编码器,需要在编码时指定它。例如:

Swift

let person = Person(name: "John Doe", age: 30, birthDate: Date())
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .formatted(DateEncoder())
do {
    let jsonData = try encoder.encode(person)
    print(String(data: jsonData, encoding: .utf8)!)
} catch {
    print("Error encoding person: \(error)")