Json Decoding 어떤 문제로 실패한걸까??

2023. 2. 25. 18:01IOS

반응형
guard let assetData = NSDataAsset(name: "JsonName") else { return }

do {
    members = try jsonDecoder.decode([Member].self, from: assetData.data)
} catch {
    print(error.localizedDescription)
}
  • 일반적으로 위와같이 Asset의 데이터를 디코딩 할 경우 Decoding이 안되는 경우가 있다.
  • Json파일 문제일 경우, Decodable 객체에 문제가 있는 경우 등이 있다.
  • 이를 조금 더 깊숙히 보기 위해서 우리는 decode메소드에 대해 알아볼 필요가 있을 것 같다.

JsonDecoder decode method

decode(_:from:) | Apple Developer Documentation

func decode<T>(
    _ type: T.Type,
    from data: Data
) throws -> T where T : Decodable
  • 해당 메소드를 보면 type과 data 두가지의 파라미터를 받는 모습을 볼 수 있다.

  • type의 경우 메타타입을 받는다. 맨 위의 예제를 볼 경우 [Member]배열의 메타타입을 주기 위해 뒤쪽에 .self를 붙여서 메타타입을 전달해준다.

  • data의 경우 Data타입을 받으므로 NSDataAsset에서 data프로퍼티를 통해 Data타입으로 메소드 인자에 전달을 한다.

  • 또한 type의 T제너릭 타입은 Decodable타입 즉 Decodable프로토콜을 채택한 타입만이 허용된다는 것 역시 볼 수 있다.

  • 다만, 우리는 Decoding실패의 이유를 파악하여야하기 때문에 throws 즉 에러를 반환해주는거를 봐야될 것 같다.

DecodingError

DecodingError | Apple Developer Documentation

  • decode메소드는 DecodingError라는 Error타입을 반환해준다.
  • 여러가지의 타입 메소드와 nested Type인 Context구조체를 포함하는 열거형인데 이 중 각각의 Case에 대해 알아보면 좋을 것 같다.

dataCorrupted

  • 데이터 즉 Json이 손상되었거나 타입과 유효하지 않다는 의미

keyNotFound

  • 디코딩 컨테이너(Decodable을 채택한 타입)의 key를 Json에 요청했지만 존재하지 않는다는 의미

typeMismatch

  • key값을 통해 값을 확인했지만, 해당 프로퍼티의 타입과 Json타입의 프로퍼티가 일치하지 않는 경우

valueNotFound

  • 디코딩 타입의 프로퍼티는 옵셔널이 아님에도 불구하고 Json내에서 값이 없는 경우

DecodingError 사용하기

do {
    members = try jsonDecoder.decode([Member].self, from: assetData.data)
} catch let DecodingError.dataCorrupted(context) {
    print(context)
} catch let DecodingError.keyNotFound(key, context) {
    print("Key '\(key)' not found:", context.debugDescription)
    print("codingPath:", context.codingPath)
} catch let DecodingError.valueNotFound(value, context) {
    print("Value '\(value)' not found:", context.debugDescription)
    print("codingPath:", context.codingPath)
} catch let DecodingError.typeMismatch(type, context)  {
    print("Type '\(type)' mismatch:", context.debugDescription)
    print("codingPath:", context.codingPath)
} catch {
    print("error: ", error)
    print(error.localizedDescription)
}
  • do-catch문에서 해당 Error의 case를 적음으로 해당 오류를 확인할 수 있다.

  • context같은 경우 DecodingError의 nestedType의 구조체인데 해당 구조체는 세가지의 프로퍼티를 가지고 있다.

    1. codingPath: [CodingKey] - 디코딩 호출이 실패한 부분에 대한 설명
    2. debugDescription: String - 무엇이 잘못된건지에 대한 설명
    3. underlyingError: (Error)? - 에러가 발생한 근본적인 에러의 타입

참고자료

반응형