【发布时间】:2019-12-31 13:24:10
【问题描述】:
得到以下数据模型:
class ResponseMultipleElements<Element: Decodable>: Decodable {
let statuscode: Int
let response_type: Int
let errormessage: String?
let detailresponse: Element?
}
class Element<T: Decodable>: Decodable {
let count: String;
let element: T?
}
对于以下 API 响应结构:
{
"statuscode": 200,
"response_type": 3,
"errormessage": null,
"detailresponse": {
"count": "1",
"campaigns": [
{
"id": 1,
"name": "Foo",
"targetagegroup": null,
"creator":...
...
}
}
}
我正在像这样触发 JSONDecoder:
class APIService: NSObject {
func getCampaignList(completion: @escaping(Result<[Campaign], APIError>) -> Void) {
guard let endpoint = URL(string: apiBaseUrlSecure + "/campaignlist") else {fatalError()}
var request = URLRequest(url: endpoint)
request.addValue("Bearer " + UserDefaults.standard.string(forKey: "authtoken")!, forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
let dataTask = URLSession.shared.dataTask(with: request) { data, response, error in
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200, let jsonData = data
else { print("ERROR: ", error ?? "unknown error"); completion(.failure(.responseError)); return }
do {
let response = try JSONDecoder().decode(ResponseMultipleElements<[Campaign]>.self, from: jsonData)
completion(.success(response.detailresponse!))
} catch {
print("Error is: ", error)
completion(.failure(.decodingError))
}
}
dataTask.resume()
}
...
}
我终于尝试像这样使用解码的活动对象
class CoopOverviewViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
//do stuff
// load Campaigns
self.apiService.getCampaignList(completion: {result in
switch result {
case .success(let campaigns):
DispatchQueue.main.async {
print("CAMPAIGN DATA: ", campaigns[0].name)
}
case .failure(let error):
print("An error occured \(error.localizedDescription)")
}
})
...
}
现在我有 2 个问题:
1)
let element: T?
在此调用的 api 响应中实际上称为“活动”。但是,它可能是其他 api 响应中的合作、支付等,具有相同的 ResponseMultipleElements 周围结构。有没有办法在这里使键可交换,就像我使用泛型处理值一样?如果没有,我还能如何解决这个问题?
2) 我收到此错误:
typeMismatch(Swift.Array<Any>,
Swift.DecodingError.Context(codingPath:
[CodingKeys(stringValue: "detailresponse", intValue: nil)],
debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))
我已经告诉 Swift,detailresponse 的“campaigns”部分是一个campaign 对象数组——至少我在查看 api 响应时是这样理解的。但是,错误似乎说它是一本字典。首先,我不明白为什么会这样,并且真的很想理解它。其次,我不知道如何告诉它它应该期待一个字典而不是一个数组 - 这里有点与泛型混淆。
非常感谢您提前提供的帮助!
【问题讨论】:
-
值
response_type是否与campaigns、cooperations等不同的键相关?如果是,则将response_type声明为枚举并根据枚举对类型进行解码。如果有固定数量的不同类型,即使是泛型也是无关紧要的。 -
这行不通。我的问题是:根对象中
response_type中的3是否代表campaigns而其他值代表其他类型? -
在我最初的问题中,在 Element 类中,我有一个带有名为“element”的键的属性。该键可以是活动或合作,也可以是 api 返回的任何对象数组,取决于调用的端点。这与 response_type 无论如何都不对应。我已经开始将该对象的类型设为通用,但不知道如何对密钥进行同样的操作。有解决办法吗?
-
请看我的回答。
标签: swift generics codable jsondecoder