JSON parsing을 하다보면, key의 이름은 동일한데 서로 다른 타입의 값을 가진 데이터들을 파싱해야할 때가 있습니다.
예를 들어서, "value"라는 key인데 하나는 int값을 가지고 다른 하나는 string값을 가집니다.
// Int 타입인 경우
{
"value": 1
}
// String 타입인 경우
{
"value": "hat"
}
이러한 경우에는 Xcode에 에러가 보통 "typeMismatch"로 아래와 같이 나올 것입니다.
typeMismatch(
Swift.String, Swift.DecodingError.Context(
codingPath: [
CodingKeys(stringValue: "ownedNfts", intValue: nil),
_JSONKey(stringValue: "Index 0", intValue: 0),
CodingKeys(stringValue: "metadata", intValue: nil),
CodingKeys(stringValue: "attributes", intValue: nil),
_JSONKey(stringValue: "Index 0", intValue: 0),
CodingKeys(stringValue: "value", intValue: nil)],
debugDescription: "Expected to decode String but found number instead.",
underlyingError: nil)
)
typeMismatch라고 알려주었기 때문에 타입에 문제가 있다는 것은 알 수 있지만,
문제가 된 타입의 위계가 전부 나오다 보니 조금 보기가 불편합니다.
그래도 잘 에러 문구를 따라가 보면, 마지막에 "value"라고 하는 부분에서 문제가 있었다는 것을 알려주고 있는 것입니다.
"Expected to decode String but found number instead."
String을 decode하려고 했는데, 숫자가 발견되었다고 하네요.
decode할 때 사용된 데이터 모델에 "value"는 String type으로 정의되어 있는데 받아온 JSON내 "value"는 숫자 형태였다는 것을 알 수 있습니다.
이런 경우 "value" 의 값 타입을 잘못 정의해주어서 타입 미스매치 에러가 난 경우도 있지만,
앞서 말한 것 처럼 두개 이상의 타입을 갖는 경우도 있습니다.
전자의 경우는 타입을 고쳐주기만 하면 되고,
후자의 경우는 enum으로 분기 처리해서 해결하면 됩니다.
Solution
struct NFTAttribute: Codable {
let value: Value // 다수의 타입(String, Int)을 갖는 key
let traitType: String
}
enum Value: Codable {
case string(String) // String 타입의 값이 발견된 경우
case number(Int) // Int 타입의 값이 발견된 경우
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let x = try? container.decode(String.self) {
self = .string(x)
return
}
if let x = try? container.decode(Int.self) {
self = .number(x)
return
}
throw DecodingError.typeMismatch(Value.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Value"))
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .string(let x):
try container.encode(x)
case .number(let x):
try container.encode(x)
}
}
}
1. enum의 case에 발견될 수 있는 타입을 나열해 줍니다.
2. init 에서 분기 처리를 해줍니다.
3. encode도 마찬가지로 분기처리를 해줍니다.
제 경우는 "value"가 String이나 Int만 갖기 때문에 두 가지만으로 분기 처리를 해주었지만,
다른 타입의 경우는 해당되는 타입들로 분기처리를 해주면 됩니다.
'Swfit' 카테고리의 다른 글
커스텀 UIButton 터치 인식 안되는 경우 (2) | 2023.12.06 |
---|---|
pod install 시 진행이 더뎠던 문제 (2) | 2023.11.15 |
ActivityKit으로 Dynamic Island 만들어보기! (0) | 2023.10.21 |
Property Wrapper 알아보기 (0) | 2023.10.03 |
JSONSerialization 사용방법 (0) | 2023.09.30 |