swift JSONDecoder анализирует один объект в объектном массиве - PullRequest
0 голосов
/ 18 октября 2019

У меня есть Json-файл с несколькими объектами "Dozzs". Внутри каждого объекта «Dozzs» находится один или несколько объектов «Dozzs». Таким образом, у меня есть смесь объектов "Dozzs" с одним объектом "Dozz" и "Dozzs" с массивом объектов "Dozz". Но я не могу сказать, что в моей структуре let doz: [Dozz] JSONDecoder не хочет анализировать один единственный "Dozz" в массив "Dozz", если это так.

Есть ли способ для анализа(если внутри Dozzs есть только один объект Dozz), что в массив? Поэтому в моей структуре всегда есть Dozz-Array с одним или несколькими объектами, и JSONDecoder не падает.

Вот моя текущая структура:

struct Dozzs : Codable {
 let doz : Dozz?
 //let doz: [Dozz]?
  }

Вот json:

{
  "test" : [ 
    {
  "dozzs":  
                {
                    "doz": {
                        "-type": "Person",
                        "-key": "125"
                    }

      }
    },
            {
  "dozzs": [ 
                {
                    "doz": {
                        "-type": "Person",
                        "-key": "123"
                    }
                },
                {
                    "doz": {
                        "-type": "Person",
                        "-key": "124,"
                    }
                }
            ]

            }
  ]
}

Справка была бы отличной 101

Ответы [ 2 ]

1 голос
/ 18 октября 2019

Я собрал образец, надеюсь, что это поможет вам.


let json1 = """
{
"doz": {
        "dozProp1": "prop1",
        "dozProp2": "prop2"
    }
}
"""
let json2 = """
{

"doz": [
{
"dozProp1": "prop1",
"dozProp2": "prop2"
},
{
"dozProp1": "prop1_23",
"dozProp2": "prop2_34"
}
]
}
"""

public struct Doz: Decodable {
    var dozProp1: String
    var dozProp2: String
}

public enum JSONValue: Decodable {
    case arrayDoz([Doz])
    case doz(Doz)

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let value = try? container.decode([Doz].self) {
            self = .arrayDoz(value)
        } else  if let value = try? container.decode(Doz.self) {
            self = .doz(value)
        } else {
            throw DecodingError.typeMismatch(JSONValue.self, DecodingError.Context(codingPath: container.codingPath, debugDescription: "Not doz"))
        }
    }
}


public struct DecodingDoz: Decodable {
    var doz: JSONValue
}

let parsed1: DecodingDoz = try JSONDecoder().decode(DecodingDoz.self, from: json1.data(using: .utf8)!)
let parsed2: DecodingDoz = try JSONDecoder().decode(DecodingDoz.self, from: json2.data(using: .utf8)!)

print(parsed1.doz)
print(parsed2.doz)

Краткое объяснение, поэтому я создал перечисление с двумя возможными значениями для Doz и сделал if ifчтобы проверить тип Doz анализируется с помощью json, и в случае обнаружения совпадения, анализ применяется в противном случае, возникает исключение.

Счастливое кодирование

0 голосов
/ 18 октября 2019

Вы должны переопределить init из декодера и декодировать JSON. В следующем коде я сначала пытаюсь декодировать один Doz объект, если он оказывается равным nil, а затем пытаюсь декодировать массив Doz.

struct Dozzs : Decodable {
    let doz : [Dozz]?

    // Coding Keys
    enum MyDozzsKeys: String, CodingKey {
      case doz
    }

    // Overriding init
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: MyDozzsKeys.self)
        if let doz    = try? container.decode(Dozz.self, forKey: .doz) {
            self.doz  = [doz]
        } else {
            let doz   = try container.decode([Dozz].self, forKey: .doz)
            self.doz  = doz
        }
    }

 }

Update: На основе вашего JSON модель должна выглядеть примерно так:

struct Dozzs : Decodable {
    let dozzs : [Doz]?

    enum MyDozzsKeys: String, CodingKey {
      case dozzs
    }

    init(from decoder: Decoder) throws {
      let container = try decoder.container(keyedBy: MyDozzsKeys.self)
        if let doz = try? container.decode(Doz.self, forKey: .dozzs) {
            self.dozzs = [doz]
        } else {
            let doz = try container.decode([Doz].self, forKey: .dozzs)
            self.dozzs = doz
        }
    }

 }

struct Doz: Decodable {
    let doz: DozData
}

struct DozData: Decodable {
    let type: String
    let key: String
    enum CodingKeys: String, CodingKey {
        case type = "-type"
        case key = "-key"
    }
}

struct Test: Decodable {
    let test: [Dozzs]?
}

И декодировать как:

try JSONDecoder().decode(Test.self, from: jsonTest)
...