使用 Swift 网络框架,如何使 IPv4Address 和 IPv6Address 符合 Codable?
With the Swift Network Framework, how can I make IPv4Address and IPv6Address conform to Codable?
Swift 网络框架包括结构 IPv4Address
和 IPv6Address
。它们与 NWEndpoints
一起用于网络连接。 IPv6Address
结构对于验证 IPv6
地址语法和实施缩短规则也很有用。
如何使 IPv4Address
和 IPv6Address
符合 Codable?
诀窍是使用 IPv4Address.rawValue 或 IPv6Address.rawValue 字段在 Data() 结构中获取 IPv4 或 IPv6 地址。然后对数据进行编码。
解码时,可以使用Data初始化地址,处理初始化失败的情况。
也可以使用 IPv6Address.description 或 IPv6Address.debugDescription 进行编码,但不推荐这样做,因为这些描述将来可能会更改格式(thx Martin R)。
import Foundation
import Network
extension IPv6Address: Codable {
enum CodingKeys: String, CodingKey {
case ipv6Data
}
enum IPv6AddressDecodingError: Error {
case decoding(String)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
let addressData = self.rawValue
try container.encode(addressData, forKey: .ipv6Data)
}
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let addressData = try values.decode(Data.self, forKey: .ipv6Data)
guard let ipv6Address = IPv6Address(addressData) else {
throw IPv6AddressDecodingError.decoding("unable to decode IPv6 address from \(values)")
}
self = ipv6Address
}
}
IPv4Address 本质上相同:
import Foundation
import Network
extension IPv4Address: Codable {
enum CodingKeys: String, CodingKey {
case ipv4Data
}
enum IPv4AddressDecodingError: Error {
case decoding(String)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
let addressData = self.rawValue
try container.encode(addressData, forKey: .ipv4Data)
}
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let addressData = try values.decode(Data.self, forKey: .ipv4Data)
guard let ipv4Address = IPv4Address(addressData) else {
throw IPv4AddressDecodingError.decoding("unable to decode IPv4 address from \(values)")
}
self = ipv4Address
}
}
无需创建您自己的 IPv4AddressDecodingError。您可以使用其 dataCorruptedError
方法抛出 DecodingError
。顺便说一句,不需要为单个值创建 CodingKeys
枚举:
您还可以创建一个符合 RawRepresentable & Codable
的协议并将 RawValue
约束为 Codable
。这样您就可以为两个 ip 地址创建通用编码器和解码器方法:
import Network
public protocol RawRepresentableCodableProtocol: RawRepresentable & Codable
where Self.RawValue: Codable { }
public extension RawRepresentableCodableProtocol {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let rawValue = try container.decode(RawValue.self)
guard let object = Self(rawValue: rawValue) else {
throw DecodingError
.dataCorruptedError(in: container, debugDescription: "Invalid rawValue data: \(rawValue)")
}
self = object
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(rawValue)
}
}
现在我们可以扩展 RawRepresentableCodableProtocol
约束 Self
到 IPAddress
协议并提供一个易出错的 rawValue 数据初始化器:
public extension RawRepresentableCodableProtocol where Self: IPAddress {
init?(rawValue: Data) {
guard let object = Self(rawValue, nil) else { return nil }
self = object
}
}
extension IPv4Address: RawRepresentableCodableProtocol { }
extension IPv6Address: RawRepresentableCodableProtocol { }
游乐场测试:
let ipv4 = IPv4Address("1.2.33.44")! // 1.2.33.44
let dataIPv4 = try JSONEncoder().encode(ipv4) // 10 bytes
let loadedIPv4 = try JSONDecoder().decode(IPv4Address.self, from: dataIPv4) // 1.2.33.44
let ipv6 = IPv6Address("2001:db8::35:44")! // 2001:db8::35:44
let dataIPv6 = try JSONEncoder().encode(ipv6) // 26 bytes
let loadedIPv6 = try JSONDecoder().decode(IPv6Address.self, from: dataIPv6) // 2001:db8::35:44
Swift 网络框架包括结构 IPv4Address
和 IPv6Address
。它们与 NWEndpoints
一起用于网络连接。 IPv6Address
结构对于验证 IPv6
地址语法和实施缩短规则也很有用。
如何使 IPv4Address
和 IPv6Address
符合 Codable?
诀窍是使用 IPv4Address.rawValue 或 IPv6Address.rawValue 字段在 Data() 结构中获取 IPv4 或 IPv6 地址。然后对数据进行编码。
解码时,可以使用Data初始化地址,处理初始化失败的情况。
也可以使用 IPv6Address.description 或 IPv6Address.debugDescription 进行编码,但不推荐这样做,因为这些描述将来可能会更改格式(thx Martin R)。
import Foundation
import Network
extension IPv6Address: Codable {
enum CodingKeys: String, CodingKey {
case ipv6Data
}
enum IPv6AddressDecodingError: Error {
case decoding(String)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
let addressData = self.rawValue
try container.encode(addressData, forKey: .ipv6Data)
}
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let addressData = try values.decode(Data.self, forKey: .ipv6Data)
guard let ipv6Address = IPv6Address(addressData) else {
throw IPv6AddressDecodingError.decoding("unable to decode IPv6 address from \(values)")
}
self = ipv6Address
}
}
IPv4Address 本质上相同:
import Foundation
import Network
extension IPv4Address: Codable {
enum CodingKeys: String, CodingKey {
case ipv4Data
}
enum IPv4AddressDecodingError: Error {
case decoding(String)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
let addressData = self.rawValue
try container.encode(addressData, forKey: .ipv4Data)
}
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let addressData = try values.decode(Data.self, forKey: .ipv4Data)
guard let ipv4Address = IPv4Address(addressData) else {
throw IPv4AddressDecodingError.decoding("unable to decode IPv4 address from \(values)")
}
self = ipv4Address
}
}
无需创建您自己的 IPv4AddressDecodingError。您可以使用其 dataCorruptedError
方法抛出 DecodingError
。顺便说一句,不需要为单个值创建 CodingKeys
枚举:
您还可以创建一个符合 RawRepresentable & Codable
的协议并将 RawValue
约束为 Codable
。这样您就可以为两个 ip 地址创建通用编码器和解码器方法:
import Network
public protocol RawRepresentableCodableProtocol: RawRepresentable & Codable
where Self.RawValue: Codable { }
public extension RawRepresentableCodableProtocol {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let rawValue = try container.decode(RawValue.self)
guard let object = Self(rawValue: rawValue) else {
throw DecodingError
.dataCorruptedError(in: container, debugDescription: "Invalid rawValue data: \(rawValue)")
}
self = object
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(rawValue)
}
}
现在我们可以扩展 RawRepresentableCodableProtocol
约束 Self
到 IPAddress
协议并提供一个易出错的 rawValue 数据初始化器:
public extension RawRepresentableCodableProtocol where Self: IPAddress {
init?(rawValue: Data) {
guard let object = Self(rawValue, nil) else { return nil }
self = object
}
}
extension IPv4Address: RawRepresentableCodableProtocol { }
extension IPv6Address: RawRepresentableCodableProtocol { }
游乐场测试:
let ipv4 = IPv4Address("1.2.33.44")! // 1.2.33.44
let dataIPv4 = try JSONEncoder().encode(ipv4) // 10 bytes
let loadedIPv4 = try JSONDecoder().decode(IPv4Address.self, from: dataIPv4) // 1.2.33.44
let ipv6 = IPv6Address("2001:db8::35:44")! // 2001:db8::35:44
let dataIPv6 = try JSONEncoder().encode(ipv6) // 26 bytes
let loadedIPv6 = try JSONDecoder().decode(IPv6Address.self, from: dataIPv6) // 2001:db8::35:44