Parse Codable classes and avoid repetition

烂漫一生 提交于 2019-12-11 01:51:31

问题


I have a JSON response as the following:

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

As far as i can say for an app API usage http_status, success, has_error, error are shared between all APIS and thus i will create a Codable class to handle it, but the response could be different model, so here is what I'm trying to do.

I have created a general response class as the below, so this class i can use for all apis in the project to avoid duplication of same class but different names:

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
    }

}

Now i have created the response class which will handle for now the registration response:

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

And lets say i need to parse the registration the response so here is what i did, i have created a class and used both of them:

class RegistrationResponse: Codable {

    let generalResponse:GeneralResponse?
    let response: RegistrationResponseDetails?

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

So i will mainly use RegistrationResponse to parse the response which will parse "generalResponse" which includes http_status, success, has_error, error, and then response will parse the desired response object.

But at some point generalResponse object is always nil and response has the data parsed correctly, what should i do to make generalResponse get parsed without duplication in each api, because in each api i will have generalResponse object so is it possible to solve it ?

Note: I'm using Alamofire as the networking library.


回答1:


You can make your GeneralResponse generic and tell it what type to use when parsing the response:

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

Then you can give it the inner response class when you parse the json:

let generalResponse = try JSONDecoder().decode(GeneralResponse<RegistrationResponseDetails>.self, from: jsonData)
// generalResponse.response is of type RegistrationResponseDetails?



回答2:


First of all if

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

why are the class properties optional?


If the mentioned keys are the same but the value for key response is different use generics.

In most cases structs are sufficient.

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

Then create the different structs e.g.

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

and parse it

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



回答3:


For a simple case

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

class Sub:Main { 
   let id:String? 
} 

This will parse

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


来源:https://stackoverflow.com/questions/53875382/parse-codable-classes-and-avoid-repetition

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!