首页 > 解决方案 > 在 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
}

我的可编码课程如下所示

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",.....]。如何使用此可编码实现

标签: jsonswiftcodable

解决方案


以下对我有用,请注意我已经做了一些简化并删除了不需要的代码init(from:),我还删除了许多属性的 Optional

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 {$0.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)
}

推荐阅读