[带有JSONDecoder的数组与字典的响应结构

问题描述 投票:0回答:1

获得以下数据模型:

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的“广告系列”部分是一组广告系列对象-至少这是我在查看api响应时的理解。但是,错误似乎表明这是一本字典。首先,我不明白为什么会这样,我真的很想了解它。其次,我不知道如何告诉它应该期待一个字典而不是一个数组-在这里与泛型有些混淆。

非常感谢您的提前帮助!

swift generics codable jsondecoder
1个回答
0
投票

您传递了[Campaign],这将使let detailresponse:[Campaign]成为解码器,当它是字典时,解码器将考虑detailresponse一个数组

 let response = try JSONDecoder().decode(ResponseMultipleElements<Campaign>.self, from: jsonData)

class ResponseMultipleElements<Element: Decodable>: Decodable {
    let statuscode: Int
    let response_type: Int
    let errormessage: String?
    let detailresponse: Item<Element>?

}

class Item<T: Decodable>: Decodable {
    let count: String;
    let campaigns: [T]?
}
© www.soinside.com 2019 - 2024. All rights reserved.