在 swift 4 中使用可编码的数组中的嵌套字典键值

nested dictionary keys values in array using codable in swift 4

我在下面的结构中有 json

{
    "message": null,
    "data": {
        "admin": {
            "UserId": 1,
            "CUSTOMER_PROFILING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "RISK_ASSESSMENT": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "LINK_ANALYSIS": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "BENCH_MARKING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "SUSPICIOUS_TRANSACTION_REPORTING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "THRESHOLD_TRANSACTION_REPORTING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            }
        },
        "vinoth59": {
            "UserId": 15,
            "CUSTOMER_PROFILING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "RISK_ASSESSMENT": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "LINK_ANALYSIS": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "BENCH_MARKING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "SUSPICIOUS_TRANSACTION_REPORTING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "THRESHOLD_TRANSACTION_REPORTING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            }
        },
        "ba_user": {
            "UserId": 16,
            "CUSTOMER_PROFILING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "RISK_ASSESSMENT": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "LINK_ANALYSIS": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "BENCH_MARKING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "SUSPICIOUS_TRANSACTION_REPORTING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            },
            "THRESHOLD_TRANSACTION_REPORTING": {
                "id": 0,
                "total": 0,
                "high": 0,
                "low": 0,
                "medium": 0
            }
        }
    },
    "status": true
}

我的可编码 class 如下所示

struct UserRiskReportBase : Codable {
    let message : String?
    let data : [String:UserRiskReport]?
    let status : Bool?

    enum CodingKeys: String, CodingKey {

        case message = "message"
        case data = "data"
        case status = "status"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        message = try values.decodeIfPresent(String.self, forKey: .message)
        data = try values.decodeIfPresent([String:[String:BenchMarking]].self, forKey: .data)
        status = try values.decodeIfPresent(Bool.self, forKey: .status)
    }

}
struct UserRiskReport: Codable {
    let userID: Int
    let customerProfiling, riskAssessment, linkAnalysis, benchMarking: BenchMarking
    let suspiciousTransactionReporting, thresholdTransactionReporting: BenchMarking

    enum CodingKeys: String, CodingKey {
        case userID = "UserId"
        case customerProfiling = "CUSTOMER_PROFILING"
        case riskAssessment = "RISK_ASSESSMENT"
        case linkAnalysis = "LINK_ANALYSIS"
        case benchMarking = "BENCH_MARKING"
        case suspiciousTransactionReporting = "SUSPICIOUS_TRANSACTION_REPORTING"
        case thresholdTransactionReporting = "THRESHOLD_TRANSACTION_REPORTING"
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        userID = try values.decodeIfPresent(Int.self, forKey: .userID)!
        customerProfiling = try values.decodeIfPresent(BenchMarking.self, forKey: .customerProfiling)!
        benchMarking = try values.decodeIfPresent(BenchMarking.self, forKey: .benchMarking)!
        riskAssessment = try values.decodeIfPresent(BenchMarking.self, forKey: .riskAssessment)!
        suspiciousTransactionReporting = try values.decodeIfPresent(BenchMarking.self, forKey: .suspiciousTransactionReporting)!
        linkAnalysis = try values.decodeIfPresent(BenchMarking.self, forKey: .linkAnalysis)!
        thresholdTransactionReporting = try values.decodeIfPresent(BenchMarking.self, forKey: .thresholdTransactionReporting)!

    }
}

struct BenchMarking : Codable {
    let id : Int?
    let total : Int?
    let high : Int?
    let low : Int?
    let medium : Int?

    enum CodingKeys: String, CodingKey {

        case id = "id"
        case total = "total"
        case high = "high"
        case low = "low"
        case medium = "medium"
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        id = try values.decodeIfPresent(Int.self, forKey: .id)
        total = try values.decodeIfPresent(Int.self, forKey: .total)
        high = try values.decodeIfPresent(Int.self, forKey: .high)
        low = try values.decodeIfPresent(Int.self, forKey: .low)
        medium = try values.decodeIfPresent(Int.self, forKey: .medium)
    }
}

我可以获得一级钥匙

let dec = JSONDecoder()
                    dec.keyDecodingStrategy = .convertFromSnakeCase
                    let alertList = try dec.decode(UserRiskReportBase.self, from:response.data!)

                    self.userRiskReportList = alertList.data!
                    self.headerArr = Array(alertList.data!.keys)

                    print(self.headerArr)

我得到了一级键,例如 ["admin"、"vinoth59"、"ba_user"]。我需要获得二级密钥 ["CUSTOMER_PROFILING","RISK_ASSESSMENT",.....]。如何实现使用这个codable

下面对我有用,请注意,我做了一些简化并删除了不需要的代码,如 init(from:),我还删除了很多属性的可选代码

struct UserRiskReportBase : Codable {
    let message : String?
    let data : [String:UserRiskReport]
    let status : Bool?
}

struct UserRiskReport: Codable {
    let userID: Int
    let customerProfiling, riskAssessment, linkAnalysis, benchMarking: BenchMarking
    let suspiciousTransactionReporting, thresholdTransactionReporting: BenchMarking

    enum CodingKeys: String, CodingKey, CaseIterable {
        case userID = "UserId"
        case customerProfiling = "CUSTOMER_PROFILING"
        case riskAssessment = "RISK_ASSESSMENT"
        case linkAnalysis = "LINK_ANALYSIS"
        case benchMarking = "BENCH_MARKING"
        case suspiciousTransactionReporting = "SUSPICIOUS_TRANSACTION_REPORTING"
        case thresholdTransactionReporting = "THRESHOLD_TRANSACTION_REPORTING"
    }

    var allKeys: [String] {
        get {
            CodingKeys.allCases.map {[=10=].rawValue}
        }
    }
}

struct BenchMarking : Codable {
    let id : Int
    let total : Int
    let high : Int
    let low : Int
    let medium : Int
}

do {
    let result = try JSONDecoder().decode(UserRiskReportBase.self, from: data)
    for item in result.data.values {
        print("Report for user: \(item.userID)")
        print(item.customerProfiling)
        print(item.benchMarking)
        //print(...)
    }
} catch {
    print(error)
}
    let dec = JSONDecoder()
    dec.keyDecodingStrategy = .useDefaultKeys
    let alertList = try? dec.decode(UserRiskReportBase.self, from: respData!)
    print("Compelete Data: ", alertList)

    let baUser = alertList?.data["ba_user"] as? UserRiskReport
    print("ba_user", alertList?.data["ba_user"])
    print(baUser?.benchMarking.id)
    print(baUser?.thresholdTransactionReporting.total)

记得用.useDefaultKeys

替换.convertFromSnakeCase