json - 使用 Codable 将 String 元素转换为复杂类型

标签 json swift codable

上下文

当前正在解码包含以下元素的 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/

相关文章:

json - Jersey Rest Client 是否比 HttpClient 更适合调用 Restful 服务?

javascript - PHP获取的数据通过jQuery为Paragraph或P标签赋值

php - 安卓、PHP、HttpGet

swift - 在 SWIFT 中加密和解密

ios - iOS9以下版本如何支持UIStackView

swift4 - 使用 Codable 将接收到的 Int 转换为 Bool 解码 JSON

json - Swift - 参数类型不符合预期类型

php - 在 Codeigniter Controller 中处理 JSON 数据

ios - 将英语日期转换为法语、nsdate、本地化的最佳方法

swift - 使用 'CodingKeys' 枚举仅覆盖几个 JSON 键