Codable: การจัดการค่า Enum ที่ไม่ถูกต้อง
ปกป้อง codebase ของคุณ: จัดการกับค่า enum ที่ไม่คาดคิด
เคยเผชิญกับสถานการณ์ที่แอปของคุณเริ่มหยุดทำงานโดยไม่มีที่ไหนเลย ซึ่งจากการตรวจสอบพบว่าแบ็กเอนด์ให้ค่าสำหรับฟิลด์ ที่ใช้ enum บาง ฟิลด์ที่ไม่มีอยู่ใน enum ในโค้ด
พิจารณาตัวอย่างต่อไปนี้:
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")
}
โอ้ ฉันรักชา
แต่ถ้าเราเปลี่ยนfavouriteBeverage
ข้อมูล JSON จากTeaเป็นJuice (ค่าที่ไม่มีอยู่ใน enum, Beverage ) ล่ะ?
let jsonString = """
{
"name": "Shubham Bakshi",
"favouriteBeverage": "Juice"
}
""".data(using: .utf8)!
โฟกัสที่ข้อความ: “ไม่สามารถเริ่มต้นเครื่องดื่มจากน้ำผลไม้ค่าสตริงที่ไม่ถูกต้อง”
หากเป็นแอปจริงแทนที่จะเป็นโค้ด Playground แอปนั้นน่าจะขัดข้อง แล้วเราจะดูแลได้อย่างไรว่าแม้ว่าแบ็กเอนด์จะส่งค่าที่ไม่ถูกต้องในการตอบกลับแอปของเราควรจะสามารถจัดการกับมันได้แทนที่จะหยุดทำงานทันที ?
หนึ่งในวิธีที่ฉันชอบเป็นการส่วนตัว: กลไก Enum Fallback ที่ไม่ถูกต้อง
มันบอกว่ากลไก แต่เป็นโปรโตคอลที่ดูแลทุกอย่างไม่มากก็น้อย เอาล่ะ ไปเลย….
/// 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
}
รอ! นั่นคืออะไร?
ไม่ว่าแบ็กเอนด์จะส่งเรามาในฐานะอะไรfavouriteBeverage
เราก็สามารถจัดการมันได้ หรือดื่มมัน อะไรก็ตาม!
ดังนั้นรหัสที่สมบูรณ์ของเราจะมีลักษณะดังนี้:
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?")
}
แค่นั้นแหละ! มีความสุขในการเข้ารหัส!
คุณสามารถเชื่อมต่อกับฉันบนLinkedIn หรือติดต่อฉันผ่านช่องทางอื่น ๆ