解析 Codable 类 并避免重复

Parse Codable classes and avoid repetition

我有一个 JSON 回复如下:

{
  "http_status": 200,
  "success": true,
  "has_error": false,
  "error": [
    ""
  ],
  "response": {
    "token": "",
    "verified": false,
    "message": ""
  }
}

据我所知,对于应用程序 API 用法 http_status、成功、has_error、错误在所有 APIS 之间共享,因此我将创建一个 Codable class 来处理它,但响应可能是不同的模型,所以这就是我正在尝试做的。

我已经创建了一个通用的响应 class 如下,所以这个 class 我可以用于项目中的所有 api 以避免重复相同的 class 但名称不同:

class GeneralResponse:Codable {

    let http_status: Int?
    let success, has_error: Bool?
    let error: [String]?

    enum CodingKeys: String, CodingKey {
        case http_status = "http_status"
        case success = "success"
        case has_error = "has_error"
        case error = "error"
    }

    init(http_status: Int?, success: Bool?, has_error: Bool?,error: [String]?) {
        self.http_status = http_status
        self.success = success
        self.has_error = has_error
        self.error = error
    }

}

现在我已经创建了响应 class,它将暂时处理注册响应:

class RegistrationResponseDetails: Codable {
    let token: String?
    let verified: Bool?
    let message: String?

    init(token: String?, verified: Bool?, message: String?) {
        self.token = token
        self.verified = verified
        self.message = message
    }
}

假设我需要解析注册响应,这就是我所做的,我创建了一个 class 并同时使用了它们:

class RegistrationResponse: Codable {

    let generalResponse:GeneralResponse?
    let response: RegistrationResponseDetails?

    init(generalResponse: GeneralResponse?, response: RegistrationResponseDetails?) {
        self.generalResponse = generalResponse
        self.response = response
    }
}

所以我会主要使用RegistrationResponse来解析response,response会解析"generalResponse",其中包括http_status、success、has_error、error,然后response会解析想要的响应对象.

但在某些时候 generalResponse 对象总是 nil 并且 response 的数据被正确解析,我应该怎么做才能使 generalResponse 在每个 api 中得到解析而不重复,因为在每个 api 中我将有 generalResponse 对象所以有可能解决它吗?

注意:我正在使用 Alamofire 作为网络库。

对于一个简单的案例

class Main:Decodable { 
    let name:String?   // insert all shared vars 
} 

class Sub:Main { 
   let id:String? 
} 

这将解析

{
     "name" : "rr" , 
     "id" : "oo"  
}

您可以使 GeneralResponse 通用并告诉它在解析响应时使用什么类型:

class GeneralResponse<T: Codable>: Codable {
    let http_status: Int?
    let success, has_error: Bool?
    let error: [String]?
    let response: T?
}

class RegistrationResponseDetails: Codable {
    let token: String?
    let verified: Bool?
    let message: String?
}

然后你可以在解析 json:

时给它内部响应 class
let generalResponse = try JSONDecoder().decode(GeneralResponse<RegistrationResponseDetails>.self, from: jsonData)
// generalResponse.response is of type RegistrationResponseDetails?

首先如果

http_status, success, has_error, error are shared between all APIS

为什么 class 属性是可选的?


如果提到的键相同但键 response 的值不同,则使用泛型。

大多数情况下 struct 就足够了。

struct JSONParser<T : Decodable> {

    struct Response<U : Decodable> : Decodable {
        let httpStatus: Int
        let success, hasError: Bool
        let error: [String]
        let response : U
    }

    let responseData : Response<T>

    init(data: Data) throws {
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        responseData = try decoder.decode(Response.self, from: data)
    }
}

然后创建不同的结构,例如

struct RegistrationResponseDetails : Decodable {
    let token: String
    let verified: Bool
    let message: String
}

并解析它

let parser = try JSONParser<RegistrationResponseDetails>(data: data)
let registrationResponseDetails = parser.responseData.response