I have a base model -
struct BaseModel<T:Decodable>: Decodable {
let jsonData: [T]?
let status: Bool?
let message: String?
enum CodingKeys: String, CodingKey {
case jsonData = "data"
case status = "success"
case message
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
if let string = try container.decodeIfPresent(T.self, forKey: .jsonData) {
print(string)
jsonData = [string]
} else {
jsonData = nil
}
} catch DecodingError.typeMismatch {
jsonData = try container.decodeIfPresent([T].self, forKey: .jsonData)
}
status = try container.decodeIfPresent(Bool.self, forKey: .status)
message = try container.decodeIfPresent(String.self, forKey: .message)
}
}
I am getting response in two types under jsonData
Getting error while decoding if I receive response as Object. And if I choose let jsonData: T?, Then getting issue in decoding of Array response.
I am using this model in my Network Model. That looks like -
func performOperation<T:Decodable>(urlEndPoint: String, method: HTTPMethod, param: Parameters?, isJsonAvailable: Bool, completion: @escaping(_ response: T?, [T]?, String?, Bool?) ->Void) {
AF.request(urlEndPoint, method: method, parameters: param, headers: header).validate(statusCode: 200..<500).responseDecodable(of: BaseModel<T>.self, decoder: decoder) { (response) in
}
Json response in case of Object -
{
"success": true,
"data": {
"heading": "Same text 1",
"title": "Sample Text 2",
"content": "Sample text 3"
},
"message": "Api response received"
}
Json response in case of ArrayList -
{
"success": true,
"data": [
{
"id": 1,
"name": "Home"
},
{
"id": 2,
"name": "Profile"
}
],
"message": "Menu List"
}
You don't need a generic structure. Just create a optional property to assign your object in case there is no user array:
struct BaseModel {
let data: [User]
let post: Post?
let success: Bool
let message: String
}
struct User: Codable {
let id: Int
let name: String
}
struct Post: Codable {
let heading: String
let title: String
let content: String
}
extension BaseModel: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
data = try container.decode([User].self, forKey: .data)
post = nil
} catch DecodingError.typeMismatch {
data = []
post = try container.decode(Post.self, forKey: .data)
}
success = try container.decode(Bool.self, forKey: .success)
message = try container.decode(String.self, forKey: .message)
}
}
If there is other responses not shown in your post you can do the same approach above using a generic structure as well:
struct BaseModel<T: Codable> {
let array: [T]
let element: T?
let success: Bool
let message: String
}
extension BaseModel: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
array = try container.decode([T].self, forKey: .array)
element = nil
} catch DecodingError.typeMismatch {
array = []
element = try container.decode(T.self, forKey: .array)
}
success = try container.decode(Bool.self, forKey: .success)
message = try container.decode(String.self, forKey: .message)
}
}