Swift - 使用 init 初始化模型对象(来自解码器:)
Swift - Initialise model object with init(from decoder:)
下面是我的模型结构
struct MovieResponse: Codable {
var totalResults: Int
var response: String
var error: String
var movies: [Movie]
enum ConfigKeys: String, CodingKey {
case totalResults
case response = "Response"
case error = "Error"
case movies
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.totalResults = try values.decodeIfPresent(Int.self, forKey: .totalResults)!
self.response = try values.decodeIfPresent(String.self, forKey: .response)!
self.error = try values.decodeIfPresent(String.self, forKey: .error) ?? ""
self.movies = try values.decodeIfPresent([Movie].self, forKey: .movies)!
}
}
extension MovieResponse {
struct Movie: Codable, Identifiable {
var id = UUID()
var title: String
var year: Int8
var imdbID: String
var type: String
var poster: URL
enum EncodingKeys: String, CodingKey {
case title = "Title"
case year = "Year"
case imdmID
case type = "Type"
case poster = "Poster"
}
}
}
现在在 ViewModel 中,我正在使用以下代码创建该模型的实例
@Published var movieObj = MovieResponse()
但是有一个编译错误说,调用init(from decoder)
方法。在这种情况下创建模型实例的正确方法是什么?
如果您不想使用解码器,则需要添加另一个初始化程序。 Swift 当且仅当您不编写自己的初始化程序时,才免费赠送您一个。既然你有一个,你就失去了免费的一个。
再加一个:
init() {
//Your initializer code here
}
如果您尝试使用解码器 init,则需要使用解码器来调用它。例如,如果它是 Json
@Published var movieObj = try? JSONDecoder().decode(MovieResponse.self, from: <#T##Data#>)
如 Swift Language Guide 所示:
Swift provides a default initializer for any structure or class that provides default values for all of its properties and doesn’t provide at least one initializer itself.
"and 不提供至少一个初始化程序本身" 部分在这里很关键。由于您正在声明一个额外的初始化程序,您应该像这样声明您自己的初始化程序:
init(
totalResults: Int,
response: String,
error: String,
movies: [Movie]
) {
self.totalResults = totalResults
self.response = response
self.error = error
self.movies = movies
}
或将 Codable
一致性移至扩展,以便 Swift 可以为您提供默认初始化程序。这将是一种首选的方式(我个人的意见,我喜欢将额外的协议一致性转移到扩展)。
struct MovieResponse {
var totalResults: Int
var response: String
var error: String
var movies: [Movie]
}
extension MovieResponse: Codable {
enum ConfigKeys: String, CodingKey {
case totalResults
case response = "Response"
case error = "Error"
case movies
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.totalResults = try values.decodeIfPresent(Int.self, forKey: .totalResults)!
self.response = try values.decodeIfPresent(String.self, forKey: .response)!
self.error = try values.decodeIfPresent(String.self, forKey: .error) ?? ""
self.movies = try values.decodeIfPresent([Movie].self, forKey: .movies)!
}
}
下面是我的模型结构
struct MovieResponse: Codable {
var totalResults: Int
var response: String
var error: String
var movies: [Movie]
enum ConfigKeys: String, CodingKey {
case totalResults
case response = "Response"
case error = "Error"
case movies
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.totalResults = try values.decodeIfPresent(Int.self, forKey: .totalResults)!
self.response = try values.decodeIfPresent(String.self, forKey: .response)!
self.error = try values.decodeIfPresent(String.self, forKey: .error) ?? ""
self.movies = try values.decodeIfPresent([Movie].self, forKey: .movies)!
}
}
extension MovieResponse {
struct Movie: Codable, Identifiable {
var id = UUID()
var title: String
var year: Int8
var imdbID: String
var type: String
var poster: URL
enum EncodingKeys: String, CodingKey {
case title = "Title"
case year = "Year"
case imdmID
case type = "Type"
case poster = "Poster"
}
}
}
现在在 ViewModel 中,我正在使用以下代码创建该模型的实例
@Published var movieObj = MovieResponse()
但是有一个编译错误说,调用init(from decoder)
方法。在这种情况下创建模型实例的正确方法是什么?
如果您不想使用解码器,则需要添加另一个初始化程序。 Swift 当且仅当您不编写自己的初始化程序时,才免费赠送您一个。既然你有一个,你就失去了免费的一个。
再加一个:
init() {
//Your initializer code here
}
如果您尝试使用解码器 init,则需要使用解码器来调用它。例如,如果它是 Json
@Published var movieObj = try? JSONDecoder().decode(MovieResponse.self, from: <#T##Data#>)
如 Swift Language Guide 所示:
Swift provides a default initializer for any structure or class that provides default values for all of its properties and doesn’t provide at least one initializer itself.
"and 不提供至少一个初始化程序本身" 部分在这里很关键。由于您正在声明一个额外的初始化程序,您应该像这样声明您自己的初始化程序:
init(
totalResults: Int,
response: String,
error: String,
movies: [Movie]
) {
self.totalResults = totalResults
self.response = response
self.error = error
self.movies = movies
}
或将 Codable
一致性移至扩展,以便 Swift 可以为您提供默认初始化程序。这将是一种首选的方式(我个人的意见,我喜欢将额外的协议一致性转移到扩展)。
struct MovieResponse {
var totalResults: Int
var response: String
var error: String
var movies: [Movie]
}
extension MovieResponse: Codable {
enum ConfigKeys: String, CodingKey {
case totalResults
case response = "Response"
case error = "Error"
case movies
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.totalResults = try values.decodeIfPresent(Int.self, forKey: .totalResults)!
self.response = try values.decodeIfPresent(String.self, forKey: .response)!
self.error = try values.decodeIfPresent(String.self, forKey: .error) ?? ""
self.movies = try values.decodeIfPresent([Movie].self, forKey: .movies)!
}
}