使用Codable Swift解析时忽略数组中的空对象

时间:2019-03-15 13:18:34

标签: json swift parsing codable swift4.2

我正在使用快速Codable解析此API

"total": 7,
"searchResult": [
    null,
    {
        "name": "joe"
        "family": "adam"
    },
    null,
    {
        "name": "martin"
        "family": "lavrix"
    },
    {
        "name": "sarah"
        "family": "mia"
    },
    null,
    {
        "name": "ali"
        "family": "abraham"
    }
]

与此PaginationModel

class PaginationModel<T: Codable>: Codable {
    var total: Int?
    var data: T?

    enum CodingKeys: String, CodingKey {
        case total
        case data = "searchResult"
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.total = try container.decodeIfPresent(Int.self, forKey: .total)
        self.data = try container.decodeIfPresent(T.self, forKey: .data)
    }
}

User型号:

struct User: Codable {
    var name: String?
    var family: String?
}

我这样调用jsonDecoder来解析API json:

let responseObject = try JSONDecoder().decode(PaginationModel<[User?]>.self, from: json)

现在我的问题是null数组中的searchResult。它正确解析,当我访问data中的paginationModel时,我在数组中找到了null

在解析API时如何忽略所有null,结果将是一个没有任何null的数组

4 个答案:

答案 0 :(得分:2)

首先,我建议始终考虑PaginationModel由数组组成。您不必传递[User]作为通用类型,只需传递User。然后,解析器可以使用解析数组并自动处理null的知识:

class PaginationModel<T: Codable>: Codable {
    var total: Int?
    var data: [T]?

    enum CodingKeys: String, CodingKey {
        case total
        case data = "searchResult"
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.total = try container.decodeIfPresent(Int.self, forKey: .total)

        self.data = (try container.decodeIfPresent([T?].self, forKey: .data))?.compactMap { $0 }
    }
}

您可能要在此处删除可选项,而改用一些默认值:

class PaginationModel<T: Codable>: Codable {
    var total: Int = 0
    var data: [T] = []

    enum CodingKeys: String, CodingKey {
        case total
        case data = "searchResult"
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.total = (try container.decodeIfPresent(Int.self, forKey: .total)) ?? 0

        self.data = ((try container.decodeIfPresent([T?].self, forKey: .data)) ?? []).compactMap { $0 }
    }
}

答案 1 :(得分:0)

简单的解决方案,解码后过滤data

let responseObject = try JSONDecoder().decode(PaginationModel<[User?]>.self, from: data)
responseObject.data = responseObject.data?.filter{$0 != nil}

答案 2 :(得分:0)

您可以在解码中添加数组类型检查:

  required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    self.total = try container.decodeIfPresent(Int.self, forKey: .total)
    self.data = try container.decodeIfPresent(T.self, forKey: .data)

    //add the following:
    if let array =  self.data as? Array<Any?> {
        self.data = ( array.compactMap{$0} as? T)
    }
}

答案 3 :(得分:0)

注意,您可以将可能为空/零的可解码变量定义为 [Float?](或任何类型),并带有可选的 '?'在数组括号内。