Kodlanabilir: Yanlış Enum Değerlerini İşleme

May 09 2023
Kod tabanınızı koruma: beklenmedik numaralandırma değerleriyle başa çıkma Hiç uygulamanızın birdenbire çökmeye başladığı bir durumla karşılaştınız mı? Bu durum, araştırma sonucunda arka ucun, kodda numaralandırma içinde bulunmayan belirli numaralandırma tabanlı alan için bir değer sağladığını ortaya çıkardı? Şu örneği göz önünde bulundurun: Ohhh I love biraz Çay Ama JSON verilerindeki favoriBeverage'ı Tea yerine Juice (enum içinde olmayan bir değer olan Beverage) olarak değiştirirsek ne olur? Mesajın şu kısmına odaklanın: "Geçersiz Dize değerinden İçecek başlatılamıyor Meyve Suyu" Bir oyun alanı kodu yerine gerçek bir uygulama olsaydı, uygulama çökerdi. Öyleyse, arka uç yanıtta geçersiz bir değer gönderse bile, uygulamamızın tamamen çökmek yerine bununla başa çıkabilmesi gerçeğini nasıl halledeceğiz? Yollardan biri ve benim kişisel favorim:

Kod tabanınızı koruma: beklenmedik numaralandırma değerleriyle uğraşma

Unsplash'ta Kostiantyn Li'nin fotoğrafı

Uygulamanızın birdenbire çökmeye başladığı bir durumla hiç karşılaştınız mı? Bu durum, araştırma sonucunda arka ucun, kodda enum içinde bulunmayan belirli bir enum tabanlı alan için bir değer sağladığını ortaya çıkardı?

Aşağıdaki örneği göz önünde bulundurun:

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 biraz çay severim

favouriteBeverageAncak JSON verilerini Tea yerine Juice ( enum içinde olmayan bir değer olan Beverage ) olarak değiştirirsek ne olur ?

let jsonString = """
{
    "name": "Shubham Bakshi",
    "favouriteBeverage": "Juice"
}
""".data(using: .utf8)!

Mesajın şu kısmına odaklanın: "Geçersiz Dize değerinden İçecek başlatılamıyor Meyve Suyu"

Bir oyun alanı kodu yerine gerçek bir uygulama olsaydı, uygulama çökerdi. Öyleyse, arka uç yanıtta geçersiz bir değer gönderse bile, uygulamamızın tamamen çökmek yerine bunu işleyebilmesi gerçeğini nasıl halledeceğiz ?

Yollardan biri ve benim kişisel favorim: Yanlış Numaralandırma Geri Dönüş Mekanizması.

Mekanizma diyor ama aşağı yukarı her şeyi halleden bir protokol. İşte başlıyoruz….

/// 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
}

Beklemek! Bu nedir?

Arka uç bize favouriteBeverage.

Yani tam kodumuz şimdi şöyle görünecek:

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?")
}

İşte bu millet! Mutlu Kodlama!

Benimle LinkedIn üzerinden iletişime geçebilir veya diğer kanallardan benimle iletişime geçebilirsiniz.