从 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 个例子是

  1. 获取api/v1/colleges 此 API 的响应 JSON 是

    { “成功”:字符串, “学院”:[学院] }

  2. 获取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