Codable: Menangani Nilai Enum yang Salah
Menjaga basis kode Anda: berurusan dengan nilai enum yang tidak diantisipasi
Pernah menghadapi situasi di mana aplikasi Anda mulai mogok entah dari mana, yang setelah diselidiki menghasilkan bahwa backend memberikan nilai untuk bidang berbasis enum tertentu yang tidak ada di dalam enum dalam kode?
Pertimbangkan contoh berikut:
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 aku suka Teh
Tetapi bagaimana jika kita mengubah favouriteBeverage
data JSON dari Tea menjadi Juice (nilai yang tidak ada di dalam enum, Beverage )?
let jsonString = """
{
"name": "Shubham Bakshi",
"favouriteBeverage": "Juice"
}
""".data(using: .utf8)!
Fokus pada bagian pesan: “Cannot initialize Beverage from invalid String value Juice”
Jika itu adalah aplikasi yang sebenarnya dan bukan kode taman bermain, aplikasi tersebut akan macet. Jadi, bagaimana kita menjaga fakta bahwa meskipun backend mengirimkan nilai yang tidak valid dalam respons, aplikasi kita harus dapat menanganinya alih-alih langsung mogok ?
Salah satu cara, dan favorit pribadi saya: Mekanisme Fallback Enum Salah.
Dikatakan mekanisme tetapi kurang lebih merupakan protokol yang menangani semuanya. Jadi, ini dia….
/// 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
}
Tunggu! Apa itu?
Apa pun yang dikirimkan backend kepada kami favouriteBeverage
, kami akan dapat menanganinya, atau meminumnya, apa pun!
Jadi kode lengkap kita sekarang akan terlihat seperti ini:
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?")
}
Itu saja, teman-teman! Selamat Coding!
Anda dapat terhubung dengan saya di LinkedIn atau dapat menghubungi saya melalui saluran lain