Swift4关于Codable的介绍和使用

Codable的Encoding和Decoding自定义类型

使您的数据类型可编码(encodable)和可解码(decodable),以与外部表示(如JSON)兼容。

概述

许多编程任务涉及通过网络连接发送数据,将数据保存到磁盘或将数据提交给API和服务。这些任务经常要求数据在传输过程中被编码和解码成中间格式。

Swift标准库定义了一种数据编码和解码的标准方法。您通过在自定义类型上实现Encodable和Decodable协议来采用这种方法。通过采用这些协议Encoder,Decoder协议和协议的实现可以获取数据,并将其编码或解码为外部表示(如JSON或属性列表)。为了同时支持编码和解码,声明符合Codable,它Encodable和Decodable协议相结合。这个过程被称为使你的类型可编码。

自动编码和解码

使一个类型可编码的最简单的方法是使用已经存在的类型来声明它的属性Codable。这些类型包括标准库类型,如String,Int和Double; 和地基类型一样Date,Data和URL。任何类型的属性都可以自动符合Codable只是声明一致性。

考虑一个Landmark存储地标名称和创建年份的结构:

struct Landmark {
    var name: String
    var foundingYear: Int
}

向触发器Codable的继承列表添加Landmark自动一致性,以满足来自Encodable和的所有协议要求Decodable:


struct Landmark: Codable {
    var name: String
    var foundingYear: Int

    // Landmark now supports the Codable methods init(from:) and encode(to:), 
    // even though they aren't written as part of its declaration.
}

采用Codable您自己的类型,可以将它们序列化为任何内置数据格式,以及自定义编码器和解码器提供的任何格式。例如,即使Landmark结构本身不包含专门处理属性列表或JSON的代码,也可以使用和类进行编码。PropertyListEncoderJSONEncoderLandmark

同样的原则适用于由可编码的其他自定义类型组成的自定义类型。只要它的所有属性都是Codable,任何自定义类型都可以Codable。

下面的例子显示了Codable当一个location属性被添加到Landmark结构中时自动一致性的应用:


struct Coordinate: Codable {
    var latitude: Double
    var longitude: Double
}

struct Landmark: Codable {
    // Double, String, and Int all conform to Codable.
    var name: String
    var foundingYear: Int

    // Adding a property of a custom Codable type maintains overall Codable conformance.
    var location: Coordinate
}

内置的类型,如Array, Dictionary和Optional也顺应Codable只要它们含有可编码的类型。你可以添加一个Coordinate实例数组,Landmark整个结构仍然可以满足Codable。

下面的例子显示了在使用内置可编码类型添加多个属性时,自动一致性仍然如何Landmark:


struct Landmark: Codable {
    var name: String
    var foundingYear: Int
    var location: Coordinate

    // Landmark is still codable after adding these properties.
    var vantagePoints: [Coordinate]
    var metadata: [String: String]
    var website: URL?
}

独有的编码或解码

在某些情况下,您可能不需要Codable对双向编码和解码的支持。例如,某些应用程序只需要调用远程网络API,而不需要解码包含相同类型的响应。Encodable如果您只需要支持数据编码,则声明符合。相反,Decodable如果您只需要读取给定类型的数据,则声明符合。

以下示例显示Landmark了仅对数据进行编码或解码的结构的替代声明:

struct Landmark: Encodable {
    var name: String
    var foundingYear: Int
}
struct Landmark: Decodable {
    var name: String
    var foundingYear: Int
}

选择属性以使用编码键(Coding Keys)进行编码(Encoding)和解码(Decoding)

Codable类型可以声明一个符合协议的特殊的嵌套枚举。当这个枚举出现时,它的情况就是当可编码类型的实例被编码或解码时必须包含的属性的权威列表。枚举个案的名称应该与您提供给您类型中相应属性的名称相匹配。CodingKeysCodingKey

如果在解码实例时不存在属性,或者某些属性不应包含在编码表示中,则省略枚举中的属性。被省略的属性需要默认值才能使其包含的类型自动符合或。CodingKeysCodingKeysDecodableCodable

如果序列化数据格式中使用的键不匹配数据类型中的属性名称,则通过指定枚举String的原始值类型来提供替代键。您用作每个枚举案例的原始值的字符串是编码和解码期间使用的密钥名称。案例名称与其原始值之间的关联使您可以根据“Swift API设计指南”为您的数据结构命名,而不必匹配您正在建模的序列化格式的名称,标点符号和大小写。CodingKeys

以下示例在编码和解码时使用结构的属性name和替代关键字:foundingYearLandmark


struct Landmark: Codable {
    var name: String
    var foundingYear: Int
    var location: Coordinate
    var vantagePoints: [Coordinate]

    enum CodingKeys: String, CodingKey {
        case name = "title"
        case foundingYear = "founding_date"

        case location
        case vantagePoints
    }
}

手动编码和解码

如果Swift类型的结构不同于其编码形式的结构,则可以提供自定义的实现Encodable并Decodable定义自己的编码和解码逻辑。

在下面的例子中,Coordinate扩展了结构以支持elevation嵌套在容器内的属性:additionalInfo


struct Coordinate {
    var latitude: Double
    var longitude: Double
    var elevation: Double

    enum CodingKeys: String, CodingKey {
        case latitude
        case longitude
        case additionalInfo
    }

    enum AdditionalInfoKeys: String, CodingKey {
        case elevation
    }
}

由于Coordinate类型的编码形式包含第二层嵌套信息,因此类型采用Encodable和Decodable协议使用两个枚举,每个枚举列出在特定级别上使用的完整编码密钥集。

在下面的例子中,通过实现它所需要的初始化程序Coordinate来扩展结构以符合Decodable协议init(from:):


extension Coordinate: Decodable {
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        latitude = try values.decode(Double.self, forKey: .latitude)
        longitude = try values.decode(Double.self, forKey: .longitude)

        let additionalInfo = try values.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)
        elevation = try additionalInfo.decode(Double.self, forKey: .elevation)
    }
}

初始化程序Coordinate通过使用Decoder它作为参数接收的实例上的方法来填充实例。该Coordinate实例的两个属性使用由雨燕标准库提供的容器密钥的API初始化。

下面的例子展示了如何通过实现其所需的方法Coordinate来扩展结构以符合Encodable协议encode(to:):


extension Coordinate: Encodable {
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(latitude, forKey: .latitude)
        try container.encode(longitude, forKey: .longitude)

        var additionalInfo = container.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)
        try additionalInfo.encode(elevation, forKey: .elevation)
    }
}

该encode(to:)方法的这种实现颠倒了前面例子中的解码操作。

有关定制编码和解码过程时使用的容器类型的更多信息,请参阅和。KeyedEncodingContainerProtocolUnkeyedEncodingContainer

来自苹果官网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值