上下文
当前正在解码包含以下元素的 JSON 数据:
{
"events": [
{
...
"rrule": "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR",
...
}
]
}
我解析 JSON 数据并将 rrule
的值收集到字符串中。到目前为止一切顺利,一切正常。
问题
但是我想将该 String
转换为复杂的 Swift 对象(枚举/结构)。本质上,我试图根据 RFC 5545 中定义的格式解析该字符串。 .
是否可以使用 Codable (Encodable, Decodable) 来做到这一点?我知道它与 json 数据的解析有些正交......
暂定解决方案(失败)
整个结构的简化版本(仅限于解码 FREQ)如下所示:
public struct ScheduledEventList: Codable {
public let events: [ScheduledEvent]
}
public struct ScheduledEvent: Codable {
public let title: String
public let rrule: RecurrenceSchema? = nil
public init(
title: String,
rrule: RecurrenceSchema?, <---- problem
) {
self.title = title
self.rrule = rrule
}
}
public enum RecurrenceFrequency: String, Codable {
case DAILY
case WEEKLY
case MONTHLY
case YEARLY
}
public enum RecurrenceSchema: Codable {
case FREQ(RecurrenceFrequency)
private enum CodingKeys: String, CodingKey {
case FREQ
}
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
let value = try values.decodeIfPresent(String.self, forKey: .FREQ)
self = .FREQ(RecurrenceFrequency(rawValue: value!)!)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .FREQ(let freq):
try container.encode(freq.rawValue, forKey: .FREQ)
}
}
}
问题是从 JSON 数据返回的元素(当然)是一个 String
所以它提示它:
error: Playground.playground:99:12: error: cannot convert value of type 'String' to expected argument type 'RecurrenceSchema?' rrule: "FREQ=WEEKLY", ^~~~~~~~~~~~~
有什么建议吗?或者在解码之外构建解析器更好/更容易——并且只在编码/解码逻辑中处理字符串?
谢谢!
最佳答案
因此,在查看了不同的建议并深入尝试使 Codable
正常工作之后,我实际上决定根据提供的重复字符串为我的重复规则使用初始化程序.
该字符串仍然是通过 Codable 从 JSON 解析的,但这就是我停止的地方。规则的“内部”解析是使用'String.split(separator:)
完成的。然后使用一些映射/归约操作将所有标记提供给字典——然后使用字典来构造递归规则对象。早期粗略草稿如下:
public struct RecurrenceRule {
public let frequency: RecurrenceFrequency
public let durationUntil: Date?
public let durationCount: Int?
public let interval: Int?
public let byDay: [RecurrenceByDay]?
public let byMonthDay: [RecurrenceByMonthDay]?
public let byYearDay: [RecurrenceByYearDay]?
public let byWeekNo: [RecurrenceByWeekNo]?
public let byMonth: [Int]?
public let bySetPos: [RecurrenceByYearDay]?
public init(rule: String) {
let splitResult = rule
.split(separator: RecurrenceRuleSeparation.semicolon.rawValue)
.map { $0.split(separator: RecurrenceRuleSeparation.equal.rawValue)}
.map { (RecurrenceKeyword(rawValue: String($0.first!)), $0.last!) }
.reduce([RecurrenceKeyword: String]()) { result, interm in
var resultCopy = result
resultCopy[interm.0!] = String(interm.1)
return resultCopy
}
self.frequency = RecurrenceFrequency(rawValue: splitResult[RecurrenceKeyword.FREQ]!)!
[....]
}
}
可能有更好/更简单的方法来实现这一目标,但这就是我目前所拥有的。
关于json - 使用 Codable 将 String 元素转换为复杂类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53347434/