Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ObjectMapper - nested dynamic keys

I'm writing in Swift 3.1, using ObjectMapper to map my JSON response to my models.

I'm trying to map this rather complex JSON response with dynamic keys and am hoping to get some feedback on what I'm doing wrong.

A group has statistics about it's progress. It has stats broken down to years and then months. Each month within a year has results, ROI and win. The ROI and win are just percentages but the results key is fixed with the keys below, 1-5, and then some integer as a value.

My JSON

"stats": {
    "2017": {
        "1": {
            "results": {
                "1": 13,
                "2": 3,
                "3": 1,
                "4": 1,
                "5": 0
            },
            "roi": 0.40337966202464975,
            "win": 0.8181818181818182
        },
        "2": {
            "results": {
                "1": 13,
                "2": 5,
                "3": 1,
                "4": 2,
                "5": 1
            },
            "roi": 0.26852551067922953,
            "win": 0.717948717948718
        }
    }
}

My models

class GroupResponse: Mappable {
    var stats: [String: [String: StatsMonthResponse]]?

    func mapping(map: Map) {
        stats   <- map["stats"]
    }
}

class StatsMonthResponse: Mappable {
    var tips: [String: Int]?
    var roi: Double?
    var win: Double?

    func mapping(map: Map) {
        tips    <- map["results"]
        roi     <- map["roi"]
        win     <- map["win"]
    }
}

What I get

The response I get has the stats property in my GroupResponse class, as nil.

What other approach could I do to accomplish this, or change in my implementation to get this done?

like image 502
Gunnar Torfi Steinarsson Avatar asked Oct 29 '22 05:10

Gunnar Torfi Steinarsson


1 Answers

Solution

I solved my problem by mapping the JSON manually.

class GroupResponse: Mappable {

    var stats: [String: StatsYear]?

    func mapping(map: Map) {
        stats   <- map["stats"]
    }
 }

class StatsYear: Mappable {

    var months: [String: StatsMonth] = [:]

    override func mapping(map: Map) {

        for (monthKey, monthValue) in map.JSON as! [String: [String: Any]] {

            let month = StatsMonth()

            for (monthKeyType, valueKeyType) in monthValue {

                if monthKeyType == "results" {
                    let tipResultDict = valueKeyType as! [String: Int]

                    for (result, tipsForResult) in tipResultDict {
                        month.tips[result] = tipsForResult
                    }
                }
                else if monthKeyType == "roi" {
                    month.roi = valueKeyType as? Double
                }
                else if monthKeyType == "win" {
                    month.win = valueKeyType as? Double
                }
            }
            months[monthKey] = month
        }
    }
}

class StatsMonth {

    var tips: [String: Int] = [:]
    var roi: Double?
    var win: Double?
}

There's probably a better solution to this problem but this is what I'm sticking with for now.

Hopefully this helps!

like image 126
Gunnar Torfi Steinarsson Avatar answered Nov 04 '22 08:11

Gunnar Torfi Steinarsson