扩展通用类型Swift的类模型

时间:2019-09-20 09:08:33

标签: swift rx-swift moya

我正在通过Moya传递API响应并获取此值。我可以获取该对象,但是我扩展了基本响应以处理其他参数,但是扩展值似乎不起作用。期望的数据可以是对象数组,也可以只是常规对象。传递此值后,它停止工作且未获得数据,但传递了status之外的所有其他参数,例如messagedata。这是我的基本回复以及如何使用它

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"
  }
}

它也可以是数据数组

1 个答案:

答案 0 :(得分:1)

(注意:下面的所有代码都可以放在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)

仅使用struct就更简单,更少代码了:

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
}