Swift Codable протокол с рекурсивными перечислениями для кодирования JSON - PullRequest
0 голосов
/ 08 июня 2018

Я новичок в 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": []
                                }
                                ]
                   }
               ]
 }
...