首页 > 解决方案 > 在 Swift 中使用字符串路径访问结构变量

问题描述

我正在为 Swift 中的 JSON 表单构建一个自定义渲染器,以与用于我们基于 Web 的应用程序的 JSON 表单架构集成。如果你不熟悉,两个 JSON 文件用于生成 UI 表单组件并链接到后端。下面是 JSON Schema 和 JSON UI Schema 的示例,以及我从 JSON Schema 生成的 Person 结构。

范围值提供了一个字符串,可用于链接到后端人员数据的变量,但我很难弄清楚如何以可扩展的方式这样做。后端将是 Core Data 和(可能)SQLite(带有 SQLite.swift)的组合,但显示的结构将是从中提取数据的对象。我希望 Keypaths 会是这样,但我无法弄清楚如何直接从字符串生成 Keypath。我想我可以使用参考字典(字符串:Keypath),但这可能会与我们可能使用的后端失控。

在你问“为什么要这样做?”之前 答案是那是黄铜交给我的任务,所以……我必须!

JSON UI 架构:

{
  "type": "VerticalLayout",
  "elements": [
    {
      "type": "HorizontalLayout",
      "elements": [
        {
          "type": "Control",
          "scope": "#/properties/firstName"
        },
        {
          "type": "Control",
          "scope": "#/properties/lastName"
        }
      ]
    },
    {
      "type": "HorizontalLayout",
      "elements": [
        {
          "type": "Control",
          "scope": "#/properties/age"
        },
        {
          "type": "Control",
          "scope": "#/properties/dateOfBirth"
        }
      ]
    },
    {
      "type": "HorizontalLayout",
      "elements": [
        {
          "type": "Control",
          "scope": "#/properties/height"
        },
        {
          "type": "Control",
          "scope": "#/properties/gender"
        },
        {
          "type": "Control",
          "scope": "#/properties/committer"
        }
      ]
    },
    {
      "type": "Group",
      "label": "Address for Shipping T-Shirt",
      "elements": [
        {
          "type": "HorizontalLayout",
          "elements": [
            {
              "type": "Control",
              "scope": "#/properties/address/properties/street"
            },
            {
              "type": "Control",
              "scope": "#/properties/address/properties/streetnumber"
            }
          ]
        },
        {
          "type": "HorizontalLayout",
          "elements": [
            {
              "type": "Control",
              "scope": "#/properties/address/properties/postalCode"
            },
            {
              "type": "Control",
              "scope": "#/properties/address/properties/city"
            }
          ]
        }
      ],
      "rule": {
        "effect": "ENABLE",
        "condition": {
          "scope": "#/properties/committer",
          "schema": {
            "const": true
          }
        }
      }
    }
  ]
}

JSON模式:

{
  "type": "person",
  "required": [
    "age"
  ],
  "properties": {
    "firstName": {
      "type": "string",
      "minLength": 2,
      "maxLength": 20
    },
    "lastName": {
      "type": "string",
      "minLength": 5,
      "maxLength": 15
    },
    "age": {
      "type": "integer",
      "minimum": 18,
      "maximum": 100
    },
    "gender": {
      "type": "string",
      "enum": [
        "Male",
        "Female",
        "Undisclosed"
      ]
    },
    "height": {
      "type": "number"
    },
    "dateOfBirth": {
      "type": "string",
      "format": "date"
    },
    "rating": {
      "type": "integer"
    },
    "committer": {
      "type": "boolean"
    },
    "address": {
      "type": "object",
      "properties": {
        "street": {
          "type": "string"
        },
        "streetnumber": {
          "type": "string"
        },
        "postalCode": {
          "type": "string"
        },
        "city": {
          "type": "string"
        }
      }
    }
  }
}

人员结构:

struct Person: Storable {
    
    var uuid: UUID = UUID()
    var firstName: String?
    var lastName: String?
    var age: Int?
    var gender: String?
    var dateOfBirth: Date?
    var height: Double?
    var rating: Int?
    var committer: Bool?
    var address: Address?
}

struct Address: Storable {
   
    var street: String?
    var streetNumber: String?
    var postalCode: String?
    var city: String?
}

标签: swiftkeypaths

解决方案


如果它们不是 Objective-C 属性,则语言中没有任何内容可以支持这一点,因此您最终需要将字符串映射到键路径。

由于它基本上是样板代码,因此您可以使用 Sourcery 来生成映射,甚至可以使用可以解析 JSON 模式的东西来生成它。


推荐阅读