为通用类型 Swift 扩展 class 模型
Extending a class model for generic type Swift
我正在通过 Moya 传递 API 响应并获取此值。我能够获取该对象,但我扩展了一个基本响应以处理额外参数,但扩展值似乎不起作用。预期的数据可以是一个对象数组,也可以只是一个常规对象。传递此值后,它停止工作并且未获取数据,但传递了除 data
之外的所有其他参数,如 status
, message
。这是我的基本回复以及我如何使用它
class MaxResponseBase: Codable {
var status: String?
var message: String?
var pagination: Pagination?
var isSucessful: Bool {
return status == "success"
}
struct ErrorMessage {
static let passwordInvalid = " Current password is invalid."
static let loginErrorIncorrectInfo = " Incorrect username/password."
static let loginErrorAccountNotExist = " Invalid request"
}
}
class MaxResponse<T: Codable>: MaxResponseBase {
var data: T?
}
class MaxArrayResponse<T: Codable>: MaxResponseBase {
var data = [T]()
}
这是我的API登录请求
func signin(email: String, password: String) -> Observable<MaxResponse<AuthResponse>> {
return provider.rx.request(.signin(username: email, password: password))
.filterSuccess()
.mapObject(MaxResponse<AuthResponse>.self)
.asObservable()
}
我如何调整它以获取数据对象
JSON
{
"status" : "success",
"data" : {
"is_locked" : false,
"__v" : 0,
"created_at" : "2019-04-15T11:57:12.551Z"
}
}
也可以是数据数组
(注意:下面的所有代码都可以放在 Playground 中以证明它有效。)
为了解决这个问题,您必须手动编写所有初始化程序。我在下面发布了大部分代码,但我强烈建议您使用结构而不是 类。如果您使用结构和包含而不是 类 和继承,那么在各个方面都会更好。
struct Pagination: Codable { }
struct AuthResponse: Codable {
let isLocked: Bool
let __v: Int
let createdAt: Date
}
class MaxResponseBase: Codable {
let status: String?
let message: String?
let pagination: Pagination?
var isSucessful: Bool {
return status == "success"
}
struct ErrorMessage {
static let passwordInvalid = " Current password is invalid."
static let loginErrorIncorrectInfo = " Incorrect username/password."
static let loginErrorAccountNotExist = " Invalid request"
}
enum CodingKeys: String, CodingKey {
case status, message, pagination
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
status = try container.decode(String?.self, forKey: .status)
message = try? container.decode(String?.self, forKey: .message) ?? nil
pagination = try? container.decode(Pagination?.self, forKey: .pagination) ?? nil
}
}
class MaxResponse<T: Codable>: MaxResponseBase {
let data: T?
enum DataCodingKeys: String, CodingKey {
case data
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: DataCodingKeys.self)
data = try container.decode(T?.self, forKey: .data)
try super.init(from: decoder)
}
}
let json = """
{
"status" : "success",
"data" : {
"is_locked" : false,
"__v" : 0,
"created_at" : "2019-04-15T11:57:12.551Z"
}
}
"""
let data = json.data(using: .utf8)!
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd'T'HH:mm:ss.SSZ"
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let response = try decoder.decode(MaxResponse<AuthResponse>.self, from: data)
print(response)
far 更简单,代码更少,只使用一个结构:
struct AuthResponse: Codable {
struct ResponseData: Codable {
let isLocked: Bool
let __v: Int
let createdAt: Date
}
let status: String?
let data: ResponseData
}
let json = """
{
"status" : "success",
"data" : {
"is_locked" : false,
"__v" : 0,
"created_at" : "2019-04-15T11:57:12.551Z"
}
}
"""
let data = json.data(using: .utf8)!
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd'T'HH:mm:ss.SSZ"
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let response = try decoder.decode(AuthResponse.self, from: data)
print(response)
如果您确实需要 MaxResponse
类型,请将其作为协议并让您的其他类型符合它。不过我敢打赌你不需要它。
为了回应您的评论,这里有一个使用结构的通用解决方案:
struct LoginResponseData: Codable {
let isLocked: Bool
let __v: Int
let createdAt: Date
}
struct BlogResponseData: Codable {
let xxx: Bool
let yyy: Int
let createdAt: Date
}
struct BaseRresponse<ResponseData: Codable>: Codable {
let status: String?
let data: ResponseData
}
我正在通过 Moya 传递 API 响应并获取此值。我能够获取该对象,但我扩展了一个基本响应以处理额外参数,但扩展值似乎不起作用。预期的数据可以是一个对象数组,也可以只是一个常规对象。传递此值后,它停止工作并且未获取数据,但传递了除 data
之外的所有其他参数,如 status
, message
。这是我的基本回复以及我如何使用它
class MaxResponseBase: Codable {
var status: String?
var message: String?
var pagination: Pagination?
var isSucessful: Bool {
return status == "success"
}
struct ErrorMessage {
static let passwordInvalid = " Current password is invalid."
static let loginErrorIncorrectInfo = " Incorrect username/password."
static let loginErrorAccountNotExist = " Invalid request"
}
}
class MaxResponse<T: Codable>: MaxResponseBase {
var data: T?
}
class MaxArrayResponse<T: Codable>: MaxResponseBase {
var data = [T]()
}
这是我的API登录请求
func signin(email: String, password: String) -> Observable<MaxResponse<AuthResponse>> {
return provider.rx.request(.signin(username: email, password: password))
.filterSuccess()
.mapObject(MaxResponse<AuthResponse>.self)
.asObservable()
}
我如何调整它以获取数据对象
JSON
{
"status" : "success",
"data" : {
"is_locked" : false,
"__v" : 0,
"created_at" : "2019-04-15T11:57:12.551Z"
}
}
也可以是数据数组
(注意:下面的所有代码都可以放在 Playground 中以证明它有效。)
为了解决这个问题,您必须手动编写所有初始化程序。我在下面发布了大部分代码,但我强烈建议您使用结构而不是 类。如果您使用结构和包含而不是 类 和继承,那么在各个方面都会更好。
struct Pagination: Codable { }
struct AuthResponse: Codable {
let isLocked: Bool
let __v: Int
let createdAt: Date
}
class MaxResponseBase: Codable {
let status: String?
let message: String?
let pagination: Pagination?
var isSucessful: Bool {
return status == "success"
}
struct ErrorMessage {
static let passwordInvalid = " Current password is invalid."
static let loginErrorIncorrectInfo = " Incorrect username/password."
static let loginErrorAccountNotExist = " Invalid request"
}
enum CodingKeys: String, CodingKey {
case status, message, pagination
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
status = try container.decode(String?.self, forKey: .status)
message = try? container.decode(String?.self, forKey: .message) ?? nil
pagination = try? container.decode(Pagination?.self, forKey: .pagination) ?? nil
}
}
class MaxResponse<T: Codable>: MaxResponseBase {
let data: T?
enum DataCodingKeys: String, CodingKey {
case data
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: DataCodingKeys.self)
data = try container.decode(T?.self, forKey: .data)
try super.init(from: decoder)
}
}
let json = """
{
"status" : "success",
"data" : {
"is_locked" : false,
"__v" : 0,
"created_at" : "2019-04-15T11:57:12.551Z"
}
}
"""
let data = json.data(using: .utf8)!
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd'T'HH:mm:ss.SSZ"
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let response = try decoder.decode(MaxResponse<AuthResponse>.self, from: data)
print(response)
far 更简单,代码更少,只使用一个结构:
struct AuthResponse: Codable {
struct ResponseData: Codable {
let isLocked: Bool
let __v: Int
let createdAt: Date
}
let status: String?
let data: ResponseData
}
let json = """
{
"status" : "success",
"data" : {
"is_locked" : false,
"__v" : 0,
"created_at" : "2019-04-15T11:57:12.551Z"
}
}
"""
let data = json.data(using: .utf8)!
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd'T'HH:mm:ss.SSZ"
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let response = try decoder.decode(AuthResponse.self, from: data)
print(response)
如果您确实需要 MaxResponse
类型,请将其作为协议并让您的其他类型符合它。不过我敢打赌你不需要它。
为了回应您的评论,这里有一个使用结构的通用解决方案:
struct LoginResponseData: Codable {
let isLocked: Bool
let __v: Int
let createdAt: Date
}
struct BlogResponseData: Codable {
let xxx: Bool
let yyy: Int
let createdAt: Date
}
struct BaseRresponse<ResponseData: Codable>: Codable {
let status: String?
let data: ResponseData
}