Ram*_*att 68 json swift codable
Swfit 4的新Encodable/ Decodable协议使JSON(de)序列化非常令人愉快.但是,我还没有找到一种方法可以对哪些属性进行编码以及应该解码哪些属性进行细粒度控制.
我注意到从附带的CodingKeysenum中排除属性完全排除了该属性,但有没有办法进行更细粒度的控制?
Cod*_*ent 131
编码/解码的键列表由一个名为的类型控制CodingKeys.编译器可以为您合成这个,但总是可以覆盖它.
假设您不想对属性进行编码/解码s:
struct Person: Codable {
var firstName: String
var lastName: String
var nickname: String?
private enum CodingKeys: String, CodingKey {
case firstName, lastName
}
}
Run Code Online (Sandbox Code Playgroud)
这将排除nickname编码和解码.
如果您希望它是非对称的(即编码但不解码,反之亦然),您必须提供自己的实现encode(with encoder: )和init(from decoder: ):
struct Person: Codable {
var firstName: String
var lastName: String
// Since fullName is a computed property, it's excluded by default
var fullName: String {
return firstName + " " + lastName
}
private enum CodingKeys: String, CodingKey {
case firstName
case lastName
case fullName
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
firstName = try container.decode(String.self, forKey: .firstName)
lastName = try container.decode(String.self, forKey: .lastName)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(firstName, forKey: .firstName)
try container.encode(lastName, forKey: .lastName)
try container.encode(fullName, forKey: .fullName)
}
}
Run Code Online (Sandbox Code Playgroud)
小智 46
使用自定义属性包装器的解决方案
struct Person: Codable {
var firstName: String
var lastName: String
@CodableIgnored
var nickname: String?
}
Run Code Online (Sandbox Code Playgroud)
哪里CodableIgnored
@propertyWrapper
public struct CodableIgnored<T>: Codable {
public var wrappedValue: T?
public init(wrappedValue: T?) {
self.wrappedValue = wrappedValue
}
public init(from decoder: Decoder) throws {
self.wrappedValue = nil
}
public func encode(to encoder: Encoder) throws {
// Do nothing
}
}
extension KeyedDecodingContainer {
public func decode<T>(
_ type: CodableIgnored<T>.Type,
forKey key: Self.Key) throws -> CodableIgnored<T>
{
return CodableIgnored(wrappedValue: nil)
}
}
extension KeyedEncodingContainer {
public mutating func encode<T>(
_ value: CodableIgnored<T>,
forKey key: KeyedEncodingContainer<K>.Key) throws
{
// Do nothing
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们需要从结构中的大量属性中排除几个属性的解码,请将它们声明为可选属性。解开选项的代码比在 CodingKey 枚举下编写大量键要少。
我建议使用扩展来添加计算实例属性和计算类型属性。它将可编码的一致性属性与其他逻辑分开,因此提供了更好的可读性。
小智 5
另一种从编码器中排除某些属性的方法,可以使用单独的编码容器
struct Person: Codable {
let firstName: String
let lastName: String
let excludedFromEncoder: String
private enum CodingKeys: String, CodingKey {
case firstName
case lastName
}
private enum AdditionalCodingKeys: String, CodingKey {
case excludedFromEncoder
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let anotherContainer = try decoder.container(keyedBy: AdditionalCodingKeys.self)
firstName = try container.decode(String.self, forKey: .firstName)
lastName = try container.decode(String.self, forKey: .lastName)
excludedFromEncoder = try anotherContainer(String.self, forKey: . excludedFromEncoder)
}
// it is not necessary to implement custom encoding
// func encode(to encoder: Encoder) throws
// let person = Person(firstName: "fname", lastName: "lname", excludedFromEncoder: "only for decoding")
// let jsonData = try JSONEncoder().encode(person)
// let jsonString = String(data: jsonData, encoding: .utf8)
// jsonString --> {"firstName": "fname", "lastName": "lname"}
}
Run Code Online (Sandbox Code Playgroud)
相同的方法可用于解码器