当前正在解码包含以下元素的JSON数据:
{
"events": [
{
...
"rrule": "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR",
...
}
]
}
我解析JSON数据并将rrule
的值收集到字符串中。到目前为止,一切正常。
但是,我想将String
转换为复杂的Swift对象(枚举/结构)。本质上,我试图根据RFC 5545中定义的格式来解析该字符串。
是否可以使用可编码(可编码,可解码)来做到这一点?我了解它与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
,因此它抱怨它:
错误:Playground.playground:99:12:错误:无法转换的值 将'String'键入期望的参数类型'RecurrenceSchema?' 规则:“ FREQ =每周”, ^ ~~~~~~~~~~~~
有什么建议吗?还是在解码之外构建解析器会更好/更容易-只需在编码/解码逻辑中处理String即可?
谢谢!
答案 0 :(得分:0)
因此,在查看了不同的建议并尝试解决Codable
的麻烦之后,我实际上决定根据提供的重复字符串对初始化规则使用初始化程序。
仍然可以通过Codable从JSON解析字符串,但这是我停止的地方。使用'String.split(separator:)
完成规则的“内部”解析。然后,使用一些map / reduce操作将所有标记馈送到Dictionary中,然后再使用Dictionary构建递归规则对象。下面的粗糙初稿:
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]!)!
[....]
}
}
可能有更好/更容易的方法来实现这一目标,但这就是我现在要掌握的。