Codable: 잘못된 Enum 값 처리
코드베이스 보호: 예상치 못한 enum 값 처리 조사 결과 백엔드가 코드의 enum 내에 존재하지 않는 특정 enum 기반 필드에 대한 값을 제공한 것으로 밝혀져 앱이 갑자기 충돌하기 시작한 상황에 직면한 적이 있습니까? 다음 예를 생각해 보십시오. 아, 나는 Tea를 좋아합니다. 하지만 JSON 데이터의 favouriteBeverage를 Tea에서 Juice(열거형, Beverage 내에 존재하지 않는 값)로 변경하면 어떻게 될까요? "유효하지 않은 문자열 값 Juice에서 Beverage를 초기화할 수 없습니다."라는 메시지 부분에 초점을 맞춥니다. 놀이터 코드가 아닌 실제 앱이었다면 앱이 충돌했을 것입니다. 그렇다면 백엔드가 응답에 유효하지 않은 값을 보내더라도 앱이 완전히 충돌하는 대신 이를 처리할 수 있어야 한다는 사실을 어떻게 처리해야 할까요? 방법 중 하나이자 개인적으로 가장 좋아하는 방법은 다음과 같습니다.
코드베이스 보호: 예상치 못한 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 ( 열거형 Beverage 내에 존재하지 않는 값 ) 로 변경하면 어떻게 될까요 ?
let jsonString = """
{
"name": "Shubham Bakshi",
"favouriteBeverage": "Juice"
}
""".data(using: .utf8)!
"유효하지 않은 문자열 값 주스에서 음료를 초기화할 수 없습니다"라는 메시지 부분에 초점을 맞춥니다.
플레이그라운드 코드가 아닌 실제 앱이었다면 앱이 다운되었을 것입니다. 그렇다면 백엔드가 응답에 유효하지 않은 값을 보내더라도 앱이 완전히 충돌하는 대신 이를 처리할 수 있어야 한다는 사실을 어떻게 처리해야 할까요 ?
방법 중 하나이자 개인적으로 가장 좋아하는 방법은 잘못된 열거형 폴백 메커니즘입니다.
그것은 메커니즘을 말하지만 모든 것을 처리하는 프로토콜에 가깝습니다. 자, 시작합니다…
/// 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 에서 저와 연결하거나 다른 채널 을 통해 저와 연락할 수 있습니다.