es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Decodificación de un objeto de diccionario sin clave asociada.

Tengo una clase de modelo que tiene un tipo y datos, y en el backend he agregado otro diccionario que no tiene un associated codingKey para obtener los datos. ¿Cómo puedo analizar los datos en este caso?

A continuación se muestra la clase de modelo:

struct OverviewWorkout: Codable {

    enum WorkoutType: String, Codable {
        case workout
        case coach
    }

    enum WorkoutsData {
        case workout(Workout)
        case coach(CoachInstruction)
    }

    var type: WorkoutType
    var data: WorkoutsData

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        type = try container.decode(WorkoutType.self, forKey: .type)
        switch type {
        case .workout:
            let data = try container.decode(Workout.self, forKey: .data)
            self.data = .workout(data)
        case .coach:
            let data = try container.decode(CoachInstruction.self, forKey: .data)
            self.data = .coach(data)
        }
    }

    private enum CodingKeys: String, CodingKey {
        case type, data
    }
}

extension OverviewWorkout {
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        switch data {
        case .workout(let workout):
            try container.encode("workout", forKey: .type)
        case .coach(let coach):
            try container.encode("coach", forKey: .type)
        }
    }
}

Aquí está la respuesta del backend:

[
    {
        "data": {
            "data": "custom title"
        },
        "type": "coach"
    },
    {
        "data": {
            "duration": "5 min"
        }
    },
    {
        "rankMontly": 4,
        "rankWeekly": 6,
        "rankYearly": 90
    }
]

Entonces, mi pregunta es cómo puedo analizar el último objeto en la respuesta, que parece ser un objeto de tipo diccionario con pares clave-valor de rankMontly, rankWeekly, rankYearly.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Como este objeto de diccionario con pares clave-valor de rango semanal, mensual y anual no está incluido en codingKeys, necesitamos analizarlo manualmente. Podemos hacer esto agregando una clave adicional llamada “rank” a nuestro enum codingKeys, lo cual nos permitirá acceder a este diccionario. Así es como podemos modificar la clase de modelo para analizar el último objeto en la respuesta:

    struct OverviewWorkout: Codable {
    
        enum WorkoutType: String, Codable {
            case workout
            case coach
        }
    
        enum WorkoutsData {
            case workout(Workout)
            case coach(CoachInstruction)
        }
    
        var type: WorkoutType
        var data: WorkoutsData
        var rankWeekly: Int?
        var rankMonthly: Int?
        var rankYearly: Int?
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            type = try container.decode(WorkoutType.self, forKey: .type)
            switch type {
            case .workout:
                let data = try container.decode(Workout.self, forKey: .data)
                self.data = .workout(data)
            case .coach:
                let data = try container.decode(CoachInstruction.self, forKey: .data)
                self.data = .coach(data)
            }
            if let rankContainer = try? container.nestedContainer(keyedBy: AdditionalKeys.self, forKey: .rank) {
                rankWeekly = try? rankContainer.decode(Int.self, forKey: .weekly)
                rankMonthly = try? rankContainer.decode(Int.self, forKey: .monthly)
                rankYearly = try? rankContainer.decode(Int.self, forKey: .yearly)
            }
        }
    
        private enum CodingKeys: String, CodingKey {
            case type, data
            case rank
        }
    
        enum AdditionalKeys: String, CodingKey {
            case weekly
            case monthly
            case yearly
        }
    
        func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)
            switch data {
            case .workout(let workout):
                try container.encode("workout", forKey: .type)
            case .coach(let coach):
                try container.encode("coach", forKey: .type)
            }
            if let rankWeekly = rankWeekly, let rankMonthly = rankMonthly, let rankYearly = rankYearly {
                var rankContainer = container.nestedContainer(keyedBy: AdditionalKeys.self, forKey: .rank)
                try rankContainer.encode(rankWeekly, forKey: .weekly)
                try rankContainer.encode(rankMonthly, forKey: .monthly)
                try rankContainer.encode(rankYearly, forKey: .yearly)
            }
        }
    }
    

    Ahora podemos acceder a los valores de rankWeekly, rankMonthly y rankYearly decodificando los datos como un array de objetos OverviewWorkout y utilizando las propiedades opcionales en cada objeto.

Comments are closed.