首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Swift,OptionSet,Encodable:需要帮助为OptionSet编写自定义编码器以生成用户友好的JSON文件

Swift,OptionSet,Encodable:需要帮助为OptionSet编写自定义编码器以生成用户友好的JSON文件
EN

Stack Overflow用户
提问于 2022-11-04 12:28:17
回答 1查看 49关注 0票数 0

我有一个应用程序,它存储一些配置选项,我想将这些选项写入JSON文件。

我的应用程序配置/选项结构和JSON编码的简化版本..。

代码语言:javascript
复制
struct AppOptions: OptionSet, Encodable {
  let rawValue: Int
  static let optA = AppOptions(rawValue: 1 << 0)
  static let optB = AppOptions(rawValue: 1 << 1)
  static let optC = AppOptions(rawValue: 1 << 2)
  static let all: AppOptions = [.optA, .optB, .optC]
}

struct AppConfig: Encodable {
  var configName: String
  var options: AppOptions
}

let appCfg = AppConfig(configName: "SomeConfig", options: [ .optA, .optC ])

let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
let data = try encoder.encode(appCfg)
print(String(decoding: data, as: UTF8.self) )
//  {
//    "configName" : "SomeConfig",
//    "options" : 5
//  }

因此,尽管这样做有效,但是生成的JSON文件并不特别友好,因为options只是作为变量保存为原始值-> "options": 5

我更希望编码器生成更用户友好的JSON,这样选项编写起来更像一个元素数组,如下所示.

代码语言:javascript
复制
  {
    "configName" : "SomeConfig",
    "options" : [ "optA", "optC" ]
  }

我有点不知道如何创建定制的encode(to: )来实现这一点,建议或解决方案。

对于一些额外的上下文,我已经为解码部分找到了一个解决方案,可以将配置从JSON文件读取到我的应用程序中,它只是返回到一个JSON文件的编码,我需要一个解决方案。

密码包括解码部分..。

代码语言:javascript
复制
struct AppOptions: OptionSet {
  let rawValue: Int
  static let optA = AppOptions(rawValue: 1 << 0)
  static let optB = AppOptions(rawValue: 1 << 1)
  static let optC = AppOptions(rawValue: 1 << 2)
  static let all: AppOptions = [.optA, .optB, .optC]
}
extension AppOptions: Codable {
  init(from decoder: Decoder) throws {
    var container = try decoder.unkeyedContainer()
    var result: AppOptions = []
    while !container.isAtEnd {
      let optionName = try container.decode(String.self)
      guard let opt = AppOptions.mapping[optionName] else {
        let context = DecodingError.Context(
          codingPath: decoder.codingPath,
          debugDescription: "Option not recognised: \(optionName)")
        throw DecodingError.typeMismatch(String.self, context)
      }
      result.insert(opt)
    }
    self = result
  }

//  func encode(to encoder: Encoder) throws {
//    // What to do here?
//  }

  private static let mapping: [String: AppOptions] = [
    "optA" : .optA,
    "optB" : .optB,
    "optC" : .optC,
    "all"   : .all
  ]
}


struct AppConfig: Codable {
  var configName: String
  var options: AppOptions
}

var json = """
{
  "configName": "SomeConfig",
  "options": ["optA", "optC"]
}
"""

let decoder = JSONDecoder()
var appCfg = try decoder.decode(AppConfig.self, from: Data(json.utf8))
print(appCfg)
//Correct ->  AppConfig(configName: "SomeConfig", options: __lldb_expr_115.AppOptions(rawValue: 5))

let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
let data = try encoder.encode(appCfg)
print(String(decoding: data, as: UTF8.self) )
//  {
//    "configName" : "SomeConfig",
//    "options" : 5
//  }
//  needs to be...
//  {
//    "configName" : "SomeConfig",
//    "options" : [ "optA", "optC" ]
//  }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-04 13:01:48

您可以这样做,但我不确定您是否正在以它应该使用的方式使用OptionSet。

代码语言:javascript
复制
func encode(to encoder: Encoder) throws {
  var container = encoder.unkeyedContainer()

  let optionsRaw: [String]
  if self == .all {
    optionsRaw = ["all"]
  } else {
    optionsRaw = Self.mapping
      .filter { $0.key != "all" }
      .compactMap { self.contains($0.value) ? $0.key : nil }
      .sorted() // if sorting is important
  }
  try container.encode(contentsOf:  optionsRaw)
}

这以一种只编码“所有”的方式处理all,并对密钥进行排序,以防它是一个子集。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74317080

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档