Я новичок в Swift Codable и пытаюсь кодировать "сложную" структуру JSON из себя.Это немного сложно, потому что оно должно быть рекурсивным.
Я нашел решение по переполнению стека для ревизионных перечислений, но я не смог реализовать его для моего JSON в Swift.( Swift Codable протокол с рекурсивными перечислениями ) Я получил решение для Python, но в Swift все гораздо сложнее.
Файл JSON будет выглядеть примерно так:
[
{
"id": 0,
"name": "Simple Rule A",
"operations": {
"attribute": "C",
"value": false
}
},
{
"id": 1,
"name": "Simple Rule A",
"operations": {
"ruleOperator": "AND",
"ruleOperand":[
{
"attribute": "A",
"value": false
},
{
"attribute": "C",
"value": false
}
]
}
},
{
"id": 2,
"name": "Simple Rule B",
"operations": {
"ruleOperator": "AND",
"ruleOperand":[
{"ruleOperator": "OR",
"ruleOperand":[
{
"attribute": "A",
"value": false
},
{
"attribute": "C",
"value": false
}
]
},
{
"attribute": "C",
"value": false
}
]
}
}
]
Это массив с правилами, и каждое правило имеет идентификатор, имя и операции.Операции могут быть "узлом" с оператором и операндами или "листьями" в качестве операнда с атрибутом и значением.
Вот что я получил:
import Foundation
struct Rule: Decodable {
let id: Int
let name: String
let operations: Operations
}
struct Operations {
//var ruleOperator: String
var ruleOperator: String?
var kind: Kind?
enum Kind {
case node([Operations])
case leaf(Operand)
}
init(name: String, ruleOp: String, kind: Kind) {
self.ruleOperator = ruleOp
self.kind = kind
}
}
extension Operations: Decodable {
enum CodingKeys: String, CodingKey {
case name
case ruleOperator
case nodes
case test
}
enum CodableError: Error {
case decoding(String)
case encoding(String)
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let someRuleOperator = try? container.decode(String.self, forKey: .ruleOperator) {
self.ruleOperator = someRuleOperator
}
if let someOperand = try container.decodeIfPresent(Operand.self, forKey: .nodes) {
self.kind = .leaf(someOperand)
}
if let array = try? container.decode([Operations].self, forKey: .nodes) {
self.kind = .node(array)
}
return
}
}
struct Operand: Decodable {
let attribute: String
let value: Bool
}
enum Operator {
case IS
case AND
case OR
case XOR
}
Проблема в том, что "init (from decoder: Decoder) "часть.Также "ruleOperator: String?"необязательным является дерьмо.
Может быть, кто-то может мне помочь :) и дать мне подсказку в правильном направлении.
(Также неплохо было бы помочь, как я могу вместо этого использовать перечисление Operatorстроки, например, "IS" или "AND".)
Решение
Переработать структуру JSON и использовать это решение Протокол Swift Codable с рекурсивными перечислениями
{
"id": 1,
"name": "Simple Rule A",
"operations": [
{
"attribute": "AND",
"value": null,
"operations": [
{
"attribute": "A",
"value": true,
"operations": []
},
{
"attribute": "B",
"value": true,
"operations": []
}
]
}
]
}