Codable
프로토콜을 사용하여 웹 API에서 JSON을 디코딩했습니다. 내 Swift
이 API의 데이터 모델에는 클래스 상속 (하위 클래스)과 컴포지션 (다른 개체의 속성으로 사용되는 개체)이 모두 포함됩니다. JSON에서 동일한 속성 이름은 완전한 객체 또는 데이터베이스에서 해당 객체의 ID를 나타내는 단일 문자열을 나타낼 수 있습니다.decoder.container (keyedBy :)가 DecodingError.typeMismatch 오류를 발생시킵니다. 코드 가능 버그?
Codable
을 사용하는 JSON을 처리하는 유일한 패턴은 객체의 초기화 자 init(from decoder: Decoder)
내에서 "수동으로"디코딩을 수행하고 먼저 전체 객체를 디코딩하려고하는 것입니다. 실패하면 (catch해야하는 오류를 던짐) String
과 동일한 속성의 디코딩을 다시 시도하십시오.
varient 속성을 포함하는 개체가 다른 Decodable
클래스의 하위 클래스가 아닌 한이 방법은 잘 작동합니다. 이 경우 기본 클래스의 속성을 디코딩하면 decoder.container(keyedBy:)
함수를 호출 할 때 DecodingError.typeMismatch
오류가 발생합니다.
아래 샘플 코드를 참조하십시오.
알려진 버그입니까? 그리고/또는이 상황에서 디코딩의 다른 방법이 빠졌습니까?
덧붙여 말하자면, DecodingError.typeMismatch
오류가 발생한 후에도 decoder.container(keyedBy:)
이 호출되면 동일한 오류가 발생합니다. 오류가 발견 된 경우에도 마찬가지입니다.
import Foundation
// A `Base` class
class Base: Codable {
var baseProperty: String? = "baseProperty"
init() {}
private enum CodingKeys: String, CodingKey { case baseProperty }
required init(from decoder: Decoder) throws {
//===>> The next line will throw DecodingError.typeMismatch
let container = try decoder.container(keyedBy: CodingKeys.self)
baseProperty = try container.decode(String.self, forKey: .baseProperty)
}
}
// A Subclass of `Base`
class Sub: Base {
// An `Other` class which is a property of the `Sub` class
class Other: Codable { var id: String? = "otherID" }
var subProperty: Other? = nil
override init() { super.init() }
private enum CodingKeys: String, CodingKey { case subProperty }
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do { subProperty = try container.decode(Other.self,
forKey: .subProperty)
}
catch { // We didn't find a whole `Other` object in the JSON; look for a `String` instead
let s = try container.decode(String.self, forKey: .subProperty)
subProperty = Other()
subProperty?.id = s
}
try super.init(from: decoder)
}
}
// Some sample JSON data:
let json = """
{"baseProperty" : "baseProperty",
"subProperty" : "someIDString"}
""".data(using: .utf8)!
// MAIN program -----------------------------------------------------
// Decode the JSON to produce a new Sub class instance
do {
_ = try JSONDecoder().decode(Sub.self, from: json)
}
catch DecodingError.typeMismatch(_, let context) {
print("DecodingError.typeMismatch: \(context.debugDescription)")
print("DecodingError.Context: codingPath:")
for i in 0..<context.codingPath.count { print(" [\(i)] = \(context.codingPath[i])") }
}
나는 당신에게 맥주를 빚지고있다. ;-) –