从 swift 中的不同 JSON 响应中获取特定值?
Getting a particular value from different JSON responses in swift?
我有一个名为 College 的模型
class College : Decodable {
let name : String
let id : String
let iconUrl : String
}
还有一些大学相关的 APIs,每个人的反应都略有不同。 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: { [=11=].stringValue == "success" })
let pKey = container.allKeys.first(where: { [=11=].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。它是一个 cocoapod 框架。你可以像这样使用 SwiftyJSON。
let json = try! JSON(data: dataFromServer)
json["success"].boolValue
json["college"]["name"].stringValue
我有一个名为 College 的模型
class College : Decodable {
let name : String
let id : String
let iconUrl : String
}
还有一些大学相关的 APIs,每个人的反应都略有不同。 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: { [=11=].stringValue == "success" })
let pKey = container.allKeys.first(where: { [=11=].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。它是一个 cocoapod 框架。你可以像这样使用 SwiftyJSON。
let json = try! JSON(data: dataFromServer)
json["success"].boolValue
json["college"]["name"].stringValue