Swift Decodable-제네릭 유형을 피하는 방법?

Aug 19 2020

JSON REST API에서 복잡한 중첩 객체를 검색하고 있습니다.

DocumentDraft
 - uuid: String
 - schema: Schema // Very complicated object with many variations
 - url: String
 - values: [Value]
 - successors: [String]
 - predecessors: [String]

Value
 - key: String
 - val: String? OR [String]?   // <-- This is the problem

이를 처리하는 적절한 방법은 제네릭 유형을 도입하는 것입니다.

struct Value<V: Decodable>: Decodable {
  let key: String
  let val: V?
}

...하지만 그래도 values혼합 배열이 될 수 있으므로 무엇을 선언하는 V것이 도움이 될지 모르겠습니다 .

그러나 물론 제네릭 유형은 계층 구조, DocumentDraft개체, 게시자, API 호출 등 으로 전파 되어 매우 깨끗하고 읽기 쉬운 호출 및 개체의 전체 체인을 오염시킵니다. 이 문제는 수준에서만 처리 Value하고 JSONDecoder가 어떻게 든 둘 중 하나를 반환하도록합니다.

옵션의 두 가지 가능성을 다루는 또 다른 방법이 val아니라 하나 String또는 [String]전체 부모 개체를 변경하지 않고는?

답변

4 gcharita Aug 19 2020 at 12:31

[String]유형 만 사용하고 다음 과 같이 프로토콜 의 init(from:)기능을 수동으로 구현 하여이를 달성 할 수 있습니다 Decodable.

struct Value: Decodable {
    let key: String
    let val: [String]?
    
    enum CodingKeys: String, CodingKey {
        case key, val
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        key = try container.decode(String.self, forKey: .key)
        do {
            if let string = try container.decodeIfPresent(String.self, forKey: .val) {
                val = [string]
            } else {
                val = nil
            }
        } catch DecodingError.typeMismatch {
            val = try container.decodeIfPresent([String].self, forKey: .val)
        }
    }
}

String값으로 디코딩이 성공하면 요소가 하나만있는 문자열 배열을 만듭니다. String값에 대한 디코딩이 실패하면 다음과 같이 디코딩하십시오.[String]