[Swift] enum에 정의되지 않은 값으로 디코딩을 시도할 때 발생하는 문제

Decoding enum with invalid value

문제 상황

struct ResponseModel: Codable {
var title: String?
var pageType: PageType?
enum PageType: Int, Codable {
case zero = 0
}
}
//정의되지 않은 pageType 이 들어옴
let jsonString = "{\"title\":\"My Title\",\"pageType\":1}"
let result = try? JSONDecoder().decode(ResponseModel.self, from: jsonString.data(using: .utf8)!)
print(result?.title ?? "nil") //nil
print(result?.pageType ?? "nil") //nil

해결 방법

1. enum 안에 init(from:) 구현

enum PageType: Int, Codable {
case zero = 0
case unknown
init(from decoder: Decoder) throws {
self = try PageType(rawValue: decoder.singleValueContainer().decode(RawValue.self)) ?? .unknown
}
}
print(result?.title ?? "nil") //My Title
print(result?.pageType ?? "nil") //.unknown

2. Model 안에 init(from:) 구현

struct ResponseModel: Codable {  var title: String?
var pageType: PageType?
enum PageType: Int, Codable {
case zero = 0
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
title = try? values.decode(String.self, forKey: .title)
pageType = try? values.decode(PageType.self, forKey: .pageType)
}
}
print(result?.title ?? "nil") //My Title
print(result?.pageType ?? "nil") //nil

추가 배경 지식 — json decode와 에러 핸들링 (feat. try)

//Call can throw, but it is not marked with 'try' and the error is not handled
let result = JSONDecoder().decode(ResponseModel.self, from: data)

1. try catch

do {
let result = try JSONDecoder().decode(ResponseModel.self, from: data)
} catch {
print(error)
}
dataCorrupted(Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "pageType", intValue: nil)], debugDescription: "Cannot initialize PageType from invalid Int value 1", underlyingError: nil))

2. try?

let result = try? JSONDecoder().decode(ResponseModel.self, from: data)print(result?.title ?? "nil") //nil
print(result?.pageType ?? "nil") //nil

3. try!

let result = try! JSONDecoder().decode(ResponseModel.self, from: data)

참고

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store