Swift 如何以通用格式编写代码表
我已经了解了如何为服务响应结构创建可编码的包装器类。 但有时在服务器端,属性值会发生变化,它可能是Int或String 范例Swift 如何以通用格式编写代码表,swift,generics,codable,Swift,Generics,Codable,我已经了解了如何为服务响应结构创建可编码的包装器类。 但有时在服务器端,属性值会发生变化,它可能是Int或String 范例 struct ResponseDataModel : Codable{ let data : DataClass? enum CodingKey: String, CodingKey{ case data = "data" } init(from decoder: Decoder) throw {
struct ResponseDataModel : Codable{
let data : DataClass?
enum CodingKey: String, CodingKey{
case data = "data"
}
init(from decoder: Decoder) throw {
let values = try decoder.container(keyedBy: CodingKeys.self)
data = try values.decodeIfPresent(DataClass.self, forKey:.data)
}
}
struct DataClass : Codable{
let id : Int
let name : String?
let age : Int?
enum CodingKey: String, CodingKey{
case id = "id"
case name = "name"
case age = "age"
}
init(from decoder: Decoder) throw {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decodeIfPresent(Int.self, forKey:.it)
name = try values.decodeIfPresent(String.self, forKey:.name)
age = try values.decodeIfPresent(Int.self, forKey:.age)
}
}
我想使用通用的方法,如果id int字符串,不管它应该绑定到具有id值数据的控制器上
let id : <T>
let id:
如何以通用格式编写代码表。您可以使用以下模型完成此操作:
struct ResponseDataModel<T: Codable>: Codable{
let data : DataClass<T>?
enum CodingKeys: String, CodingKey{
case data = "data"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
data = try values.decodeIfPresent(DataClass<T>.self, forKey:.data)
}
}
struct DataClass<T: Codable>: Codable {
let id: T?
let name: String?
let age: Int?
enum CodingKeys: String, CodingKey{
case id = "id"
case name = "name"
case age = "age"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
id = try values.decodeIfPresent(T.self, forKey:.id)
name = try values.decodeIfPresent(String.self, forKey:.name)
age = try values.decodeIfPresent(Int.self, forKey:.age)
}
}
或者,您可以使用以下模型始终将id
映射为Int
,即使您的服务器将其作为String
发送:
struct ResponseDataModel: Codable{
let data : DataClass?
enum CodingKeys: String, CodingKey{
case data = "data"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
data = try values.decodeIfPresent(DataClass.self, forKey:.data)
}
}
struct DataClass: Codable {
let id: Int?
let name: String?
let age: Int?
enum CodingKeys: String, CodingKey{
case id = "id"
case name = "name"
case age = "age"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
do {
id = try values.decodeIfPresent(Int.self, forKey:.id)
} catch DecodingError.typeMismatch {
if let idString = try values.decodeIfPresent(String.self, forKey:.id) {
id = Int(idString)
} else {
id = nil
}
}
name = try values.decodeIfPresent(String.self, forKey:.name)
age = try values.decodeIfPresent(Int.self, forKey:.age)
}
}
根据提供的示例,您可以通过尝试解码每种类型的值来达到所需的结果
struct响应:可解码{
let id:String
名称:字符串?
让年龄:Int?
私有枚举编码键:字符串,编码键{
案例数据
}
私有枚举嵌套编码键:字符串,编码键{
病例id
案例名称
病例年龄
}
init(来自解码器:解码器)抛出{
let container=try decoder.container(keyedBy:CodingKeys.self)
让nestedContainer=try container.nestedContainer(
keyedBy:NestedCodingKeys.self,
forKey:。数据
)
如果let id=try?nestedContainer.decode(Int.self,forKey:.id){
self.id=字符串(id)
}否则{
id=尝试nestedContainer.decode(String.self,forKey:.id)
}
name=尝试nestedContainer.decodeIfPresent(String.self,forKey:.name)
age=尝试nestedContainer.decodeIfPresent(Int.self,forKey:.age)
}
}
您也可以捕获
DecodingError
,但是对于特定的键值对,decode(u:forKey:)
的catch语句只起到提前退出的作用,因为它会抛出以下错误之一-typemissmatch
、keyNotFound
或valueNotFound
,以下是使用Codable
进行解析时需要注意的一些要点
enum CodingKeys
init(from:)
<如果模型按照格式正确编写,code>Codable将自动处理所有解析
ResponseDataModel
看起来
struct ResponseDataModel : Codable{
let data: DataClass?
}
现在,对于DataClass
您只需要添加一个if-else
条件来处理Int
和String
案例。这里不需要实现泛型
使用String
或Int
作为id
的类型。并相应地添加条件。在下面的代码中,我使用id
作为String
struct DataClass : Codable {
let id : String //here....
let name : String?
let age : Int?
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decodeIfPresent(String.self, forKey: .name)
age = try values.decodeIfPresent(Int.self, forKey: .age)
if let id = try? values.decode(Int.self, forKey: .id) {
self.id = String(id)
} else {
self.id = try values.decode(String.self, forKey:.id)
}
}
}
这回答了你的问题吗?使用这种逻辑,您不需要事先知道它是否是一个Int或String,您需要使用泛型解决方案,这将不会产生预期的结果。如果
id
是String
,decodeIfPresent(\uuuuxforkey:)
函数将抛出一个解码错误。类型不匹配错误以及else
语句中的任何内容将永远不会执行。@gcharita更新了该错误。谢谢,这种方法(更新后)在应该抛出错误时会忽略格式错误的JSON。@gcharita不,不会。这将由catch语句在解析decode(u:forKey:)
的数据
@gcharita do catch块时处理,因为它会抛出以下一个-类型不匹配
,因此只能作为提前退出,keyNotFound
或valueNotFound
对于该特定的键值对,为什么不投票关闭此重复项?
struct DataClass : Codable {
let id : String //here....
let name : String?
let age : Int?
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decodeIfPresent(String.self, forKey: .name)
age = try values.decodeIfPresent(Int.self, forKey: .age)
if let id = try? values.decode(Int.self, forKey: .id) {
self.id = String(id)
} else {
self.id = try values.decode(String.self, forKey:.id)
}
}
}