Codificável: lidando com valores de enumeração incorretos
Protegendo sua base de código: lidando com valores de enumeração imprevistos
Já enfrentou uma situação em que seu aplicativo começou a travar do nada, o que, após investigação, revelou que o back-end forneceu um valor para determinado campo baseado em enumeração que não existe dentro da enumeração no código?
Considere o seguinte exemplo:
import Foundation
struct Person: Codable {
let name: String
let favouriteBeverage: Beverage
}
enum Beverage: String, Codable {
case Tea
case Coffee
}
let jsonString = """
{
"name": "Shubham Bakshi",
"favouriteBeverage": "Tea"
}
""".data(using: .utf8)!
let decodedJSON = try! JSONDecoder().decode(Person.self, from: jsonString)
switch decodedJSON.favouriteBeverage {
case .Tea:
print("Ohhh I love some Tea")
case .Coffee:
print("Coffee is no Tea but meh, I'll take it")
}
Ohhh eu amo um pouco de chá
Mas e se mudarmos favouriteBeverage
os dados JSON de Tea para Juice (um valor que não existe dentro do enum, Beverage ) ?
let jsonString = """
{
"name": "Shubham Bakshi",
"favouriteBeverage": "Juice"
}
""".data(using: .utf8)!
Concentre-se na parte da mensagem: “Não é possível inicializar a bebida de um valor de string inválido Juice”
Se fosse um aplicativo real em vez de um código de playground, o aplicativo teria travado. Então, como cuidamos do fato de que, mesmo que o back-end envie um valor inválido na resposta, nosso aplicativo deve ser capaz de lidar com isso em vez de travar completamente ?
Uma das maneiras, e minha favorita: Mecanismo de fallback de enumeração incorreto.
Diz mecanismo, mas é mais ou menos um protocolo que cuida de tudo. Aqui vamos nos ….
/// This is useful in case the backend specifies some value that does not
/// exist inside the enum as in such cases the app crashes since it fails to
/// parse the enum.
///
/// This ensures that in case an invalid value is specified, the app will
/// not crash but rather resort to a value specified for
/// `fallbackForIncorrectEnumValue`
///
protocol IncorrectEnumFallbackMechanism: RawRepresentable, Codable {
/// Fallback value in case the backend returns an incorrect value for
/// the enum
static var fallbackForIncorrectEnumValue: Self { get }
}
extension IncorrectEnumFallbackMechanism where RawValue: Codable {
init(from decoder: Decoder) throws {
// Fetching the value specified inside the JSON
let value = try decoder.singleValueContainer().decode(RawValue.self)
// Creating the instance based on the provided value or falling back
// to a default value in case the provided value for creating is
// invalid
self = Self(rawValue: value) ?? Self.fallbackForIncorrectEnumValue
}
/// Since `RawRepresentable` declares a `encode(coder:)` by default so we
/// don't need to implement that explicitly
}
enum Beverage: String, IncorrectEnumFallbackMechanism {
static var fallbackForIncorrectEnumValue: Beverage = .SomeWeirdBeverage
case Tea
case Coffee
case SomeWeirdBeverage
}
Espere! O que é aquilo?
Não importa o que o back-end nos envie como favouriteBeverage
, seremos capazes de lidar com isso, ou beber, seja o que for!
Portanto, nosso código completo ficará assim:
import Foundation
/// This is useful in case the backend specifies some value that does not
/// exist inside the enum as in such cases the app crashes since it fails to
/// parse the enum.
///
/// This ensures that in case an invalid value is specified, the app will
/// not crash but rather resort to a value specified for
/// `fallbackForIncorrectEnumValue`
///
protocol IncorrectEnumFallbackMechanism: RawRepresentable, Codable {
/// Fallback value in case the backend returns an incorrect value for
/// the enum
static var fallbackForIncorrectEnumValue: Self { get }
}
extension IncorrectEnumFallbackMechanism where RawValue: Codable {
init(from decoder: Decoder) throws {
// Fetching the value specified inside the JSON
let value = try decoder.singleValueContainer().decode(RawValue.self)
// Creating the instance based on the provided value or falling back
// to a default value in case the provided value for creating is
// invalid
self = Self(rawValue: value) ?? Self.fallbackForIncorrectEnumValue
}
/// Since `RawRepresentable` declares a `encode(coder:)` by default so we
/// don't need to implement that explicitly
}
struct Person: Codable {
let name: String
let favouriteBeverage: Beverage
}
enum Beverage: String, IncorrectEnumFallbackMechanism {
static var fallbackForIncorrectEnumValue: Beverage = .SomeWeirdBeverage
case Tea
case Coffee
case SomeWeirdBeverage
}
let jsonString = """
{
"name": "Shubham Bakshi",
"favouriteBeverage": "Juice"
}
""".data(using: .utf8)!
let decodedJSON = try! JSONDecoder().decode(Person.self, from: jsonString)
switch decodedJSON.favouriteBeverage {
case .Tea:
print("Ohhh I love some Tea")
case .Coffee:
print("Coffee is no Tea but meh, I'll take it")
case .SomeWeirdBeverage:
print("Wait! What is that?")
}
É isso, pessoal! Codificação feliz!
Você pode se conectar comigo no LinkedIn ou pode entrar em contato comigo por outros canais