你能为 Codable 对象“扩展”(即添加额外的初始化逻辑)自动生成的构造函数吗?
Can you “extend” (i.e. add additional initialization logic to) the auto-generated constructor for a Codable object?
当你在一个对象上实现Codable
时,编译器会自动为你生成一个构造函数。但是,只有在您没有自己编写接受解码器的初始化程序的情况下,它才会这样做。
也就是说,我们有一个对象,它具有从解码器设置的 ~50 let
属性,但我们还有五个基于这些 let
属性的计算属性。
从技术上讲,如果我们可以在初始化程序中计算它们,在解码器设置了其他 50 个之后,我们可以简单地将结果存储在它们自己的 let
变量中,从而完全不需要计算属性。
问题是,如前所述,如果您实现自己的初始化器,编译器不会为您自动生成初始化器,因此您不仅要初始化 'computed' 值,还要初始化 全部个值。
那么,有没有一种方法可以让您将自己作为 initialization/decoding 过程的一部分插入,而不必自己完全重写初始化程序?
您要查找的内容类似于委托模式,其中解码器通知其委托它已完成解码。遗憾的是,它尚未添加到 Swift。我能想到的最接近的方法是使用继承,这样 Swift 可以为基础 class 中的那 50 个 let
自动生成解码器,并且您可以在子 class。例如:
class A: Decodable {
let firstName: String
let lastName: String
}
class B: A {
private var _fullName: String! = nil
var fullName: String { return _fullName }
required init(from decoder: Decoder) throws {
try super.init(from: decoder)
_fullName = firstName + " " + lastName
}
}
在 class A 中定义您的 50 个属性,并在 class B 中保留所有计算属性。
或者根据您的建议,您也可以使用 lazy var
:
struct Model: Decodable {
let firstName: String
let lastName: String
// private(set) so users cannot change value of the
// pre-computed property
lazy private(set) var fullName = self.firstName + " " + self.lastName
}
// But you can't use a let here, since calling fullName
// for the first time will mutate the struct
var model = try JSONDecoder().decode(Model.self, from: json)
当你在一个对象上实现Codable
时,编译器会自动为你生成一个构造函数。但是,只有在您没有自己编写接受解码器的初始化程序的情况下,它才会这样做。
也就是说,我们有一个对象,它具有从解码器设置的 ~50 let
属性,但我们还有五个基于这些 let
属性的计算属性。
从技术上讲,如果我们可以在初始化程序中计算它们,在解码器设置了其他 50 个之后,我们可以简单地将结果存储在它们自己的 let
变量中,从而完全不需要计算属性。
问题是,如前所述,如果您实现自己的初始化器,编译器不会为您自动生成初始化器,因此您不仅要初始化 'computed' 值,还要初始化 全部个值。
那么,有没有一种方法可以让您将自己作为 initialization/decoding 过程的一部分插入,而不必自己完全重写初始化程序?
您要查找的内容类似于委托模式,其中解码器通知其委托它已完成解码。遗憾的是,它尚未添加到 Swift。我能想到的最接近的方法是使用继承,这样 Swift 可以为基础 class 中的那 50 个 let
自动生成解码器,并且您可以在子 class。例如:
class A: Decodable {
let firstName: String
let lastName: String
}
class B: A {
private var _fullName: String! = nil
var fullName: String { return _fullName }
required init(from decoder: Decoder) throws {
try super.init(from: decoder)
_fullName = firstName + " " + lastName
}
}
在 class A 中定义您的 50 个属性,并在 class B 中保留所有计算属性。
或者根据您的建议,您也可以使用 lazy var
:
struct Model: Decodable {
let firstName: String
let lastName: String
// private(set) so users cannot change value of the
// pre-computed property
lazy private(set) var fullName = self.firstName + " " + self.lastName
}
// But you can't use a let here, since calling fullName
// for the first time will mutate the struct
var model = try JSONDecoder().decode(Model.self, from: json)