使用Swift JSONDecoder处理JSON

时间:2018-07-11 16:59:07

标签: json swift struct codable jsondecoder

这是我要解析的JSON

{
  "rows": [
    {
      "layout": "Y",
    },
    {
      "layout": "A",
    }
  ]
}

我希望能够过滤出不支持的布局类型。我正在使用JSONDecoder将JSON数据转换为结构,但是在处理行时遇到问题。我正在尝试使用let row = try来转换每一行? rowContainer.decode(Row.self),但除非它解码为空结构,否则我可以弄清楚如果失败将如何移至下一个。我只是尝试将其解码为Dictionary,但是除了value字段中的Any之外就不会。

enum RowType: String, Codable {
    case a = "A"
    case b = "B"
}

public struct Page: Codable {

    let rows: [Row]

    public init(from decoder: Decoder) throws {

        // Get Container
        let container = try decoder.container(keyedBy: CodingKeys.self)

        // Create Result Array
        var rowResult: [Row] = []

        // Get Rows Container
        var rowContainer = try container.nestedUnkeyedContainer(forKey: .rows)

        // Process Rows
        while !rowContainer.isAtEnd {

            // Create Row
            if let row = try? rowContainer.decode(Row.self) {
                rowResult.append(row)
            }
            else {

                // Increment Row Container
                _ = try rowContainer.decode(Empty.self)
            }
        }

        // Set Result
        rows = rowResult
    }

    // Used For Unsupported Rows
    struct Empty: Codable {}
}

public struct Row: Codable {
    let layout: RowType
}

1 个答案:

答案 0 :(得分:4)

这是另一种方法。

使用layout字符串值创建一个临时结构

public struct RawRow: Codable {
    let layout: String
}

Page中,首先将rows解码为RawRow,然后将数组compactMap解码为Row。它过滤所有layout值不能转换为枚举的项

public struct Page: Codable {
    let rows: [Row]

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let rowData = try container.decode([RawRow].self, forKey: .rows)
        rows = rowData.compactMap {
            guard let rowType = RowType(rawValue: $0.layout) else { return nil }
            return Row(layout: rowType)
        }
    }
}