Swift 使用JSONDecoder的数组与字典响应结构

Swift 使用JSONDecoder的数组与字典响应结构,swift,generics,codable,jsondecoder,Swift,Generics,Codable,Jsondecoder,获得以下数据模型: 类响应多元素:可解码{ 让状态代码:Int let响应类型:Int 让错误消息:字符串? 让我们来回答:元素? } 类元素:可解码{ 让计数:字符串; 让元素:T? } 对于以下API响应结构: { "statuscode": 200, "response_type": 3, "errormessage": null, "detailresponse": { "count": "1", "campaigns":

获得以下数据模型:

类响应多元素:可解码{
让状态代码:Int
let响应类型:Int
让错误消息:字符串?
让我们来回答:元素?
}
类元素:可解码{
让计数:字符串;
让元素: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(完成:@escaping(Result)->Void){
guard let endpoint=URL(字符串:apiBaseUrlSecure+“/campaignlist”)else{fatalError()}
var-request=URLRequest(url:endpoint)
request.addValue(“Bearer”+UserDefaults.standard.string(forKey:“authttoken”)!,forHTTPHeaderField:“Authorization”)
request.httpMethod=“GET”
让dataTask=URLSession.shared.dataTask(with:request){data,response,中的错误
guard让httpResponse=响应为?HTTPURLResponse,httpResponse.statusCode==200,让jsonData=data
else{print(“ERROR:,ERROR??“unknown ERROR”);完成(.failure(.responseError));返回}
做{
让response=try JSONDecoder().decode(ResponseMultipleElements.self,from:jsonData)
完成(.success(response.detailresponse!))
}抓住{
打印(“错误为:”,错误)
完成(.failure(.decodingError))
}
}
dataTask.resume()
}
...
}
我终于试着利用像这样解码的竞选对象了

class CoopoOverViewController:UIViewController、UICollectionViewDelegate、UICollectionViewDataSource{
重写func viewDidLoad(){
super.viewDidLoad()
//做事
//加载活动
self.apiService.getCampaignList(完成:{结果为
切换结果{
成功案例(let活动):
DispatchQueue.main.async{
打印(“活动数据:”,活动[0]。名称)
}
案例。失败(let错误):
打印(“发生错误\(error.localizedDescription)”)
}
})
...
}
现在我有两个问题:

(一)

实际上被称为“活动”在这个调用的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.Array,
Swift.DecodingError.Context(编码路径:
[编码键(stringValue:“detailresponse”,intValue:nil)],
debugDescription:“应解码数组,但找到了字典。”,underyingError:nil)
我已经告诉斯威夫特“战役”detailresponse的一部分是一个活动对象数组——至少我在查看api响应时是这样理解的。然而,错误似乎是说它是一个字典。首先,我不明白这是为什么,我真的很想理解它。其次,我不知道如何告诉它应该使用字典而不是数组-这里有点和泛型混淆了


非常感谢您的帮助!

这是一种添加自定义密钥解码策略的方法,可以将
编码密钥
中的
计数
映射到固定值
元素

首先,创建一个自定义
CodingKey

struct AnyCodingKey: CodingKey {

    var stringValue: String

    init?(stringValue: String) {
        self.stringValue = stringValue
    }

    var intValue: Int? { return nil }

    init?(intValue: Int) {
        return nil
    }
}
然后创建类似于Sh_Khan答案的结构,在大多数情况下不需要类

struct ResponseMultipleElements<T: Decodable>: Decodable {
    let statuscode : Int
    let response_type : Int
    let errormessage : String?
    let detailresponse : Element<T>
}

struct Element<U: Decodable>: Decodable {
    let count : String
    let element : U
}

struct Campaign : Decodable {
    let id : Int
    let name : String
    let targetagegroup : String?
}

response\u type
是否与不同的键
活动
合作
等相关?如果是,则声明
response\u type
为枚举,并根据枚举对类型进行解码。如果存在固定数量的不同类型,则泛型也不重要。这无法工作。我的问题是:
3
response\u type
中,在根对象中表示
活动
和其他值表示其他类型?在我的初始问题中,在class元素中,我有一个属性,其键名为“Element”。该键可以是活动或合作或api返回的任何对象数组,取决于调用的终结点。这与响应类型没有任何对应关系。我已经开始将该对象的类型设置为泛型,但不知道如何使用该键。有解决方案吗?请参阅我的答案.正是我要找的。就像一个魔术师,教了我一堂关于自定义解码策略的课。非常感谢!!!
struct ResponseMultipleElements<T: Decodable>: Decodable {
    let statuscode : Int
    let response_type : Int
    let errormessage : String?
    let detailresponse : Element<T>
}

struct Element<U: Decodable>: Decodable {
    let count : String
    let element : U
}

struct Campaign : Decodable {
    let id : Int
    let name : String
    let targetagegroup : String?
}
do {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .custom { codingKeys in
        let lastKey = codingKeys.last!
        if lastKey.intValue != nil || codingKeys.count != 2 { return lastKey }
        if lastKey.stringValue == "count" { return lastKey }
        return AnyCodingKey(stringValue: "element")!
    }
    let result = try decoder.decode(ResponseMultipleElements<[Campaign]>.self, from: data)
    completion(.success(result.detailresponse.element))
} catch {
    print("Error is: ", error)
    completion(.failure(error))
}