我有一个名为College 的模型
class College : Decodable {
let name : String
let id : String
let iconUrl : String
}
以及一些与大学相关的API,每个API的响应都略有不同。是2个例子
获取api/v1/colleges此API的响应JSON为
{"成功":一串"学院":[学院]}
获取api/v1/college/{collegeID}此API的响应JSON为
{"成功":一串"学院":学院}
现在,从这两个回复中,我只需要获得大学信息;成功;我的问题是,如何在不为每个API创建单独的响应模型的情况下获得大学信息?目前,我已经为每个API响应实现了单独的类
class GetCollegesResponse : Decodable {
let success : String
let colleges : [College]
}
class GetCollegeResponse : Decodable {
let success : String
let college : College
}
我在各自的API调用中使用它们,比如这样的
Alamofire.request(api/v1/colleges ....).responseJSON { response in
let resp = JSONDecoder().decode(GetCollegesResponse.self, response.data)
//get colleges from resp.colleges
}
Alamofire.request(api/v1/college/(id) ....).responseJSON { response in
let resp = JSONDecoder().decode(GetCollegeResponse.self, response.data)
// get college form resp.college
}
有没有更简单的方法来完成这件事?
也许正确的方法是将响应建模为泛型类型,比如这样的:
struct APIResponse<T: Decodable> {
let success: String
let payload: T
}
您可以从中提取有效载荷。
问题是有效载荷的密钥发生了变化:单个结果为college
,多个大学结果为colleges
。
如果你真的不在乎,只想要有效载荷,我们可以有效地忽略它,并将任何密钥(除了"成功"(解码为预期类型T
:
struct APIResponse<T: Decodable> {
let success: String
let payload: T
// represents any string key
struct ResponseKey: CodingKey {
var stringValue: String
var intValue: Int? = nil
init(stringValue: String) { self.stringValue = stringValue }
init?(intValue: Int) { return nil }
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: ResponseKey.self)
let sKey = container.allKeys.first(where: { $0.stringValue == "success" })
let pKey = container.allKeys.first(where: { $0.stringValue != "success" })
guard let success = sKey, let payload = pKey else {
throw DecodingError.keyNotFound(
ResponseKey(stringValue: "success|any"),
DecodingError.Context(
codingPath: container.codingPath,
debugDescription: "Expected success and any other key"))
}
self.success = try container.decode(String.self, forKey: success)
self.payload = try container.decode(T.self, forKey: payload)
}
}
然后你可以根据预期的有效载荷进行解码:
let resp = try JSONDecoder().decode(APIResponse<[College]>.self, response.data)
let colleges = resp.payload
如果不为整个响应创建模型,恐怕无法从json响应中获取特定项的值。(至少使用可编码(
首先,我们将以编码形式(UTF8(接收从服务器发送的有效载荷。因此,在使用它之前,我们必须先对其进行解码,这就是codable帮助我们解码数据的地方。如果您希望看到使用字符串的原始转换,请尝试此方法。
let dataConvertedToString = String(data: dataReceivedFromServer, encoding: .utf8)
如果您仍然喜欢从JSON响应中单独获取值,我建议您使用SwiftyJSON。它是一个茧状的框架。您可以像这样使用SwiftyJSON。
let json = try! JSON(data: dataFromServer)
json["success"].boolValue
json["college"]["name"].stringValue