如何使用Swift 4.0 Codable过滤JSON解码中的无效数据
用Swift 4.0 Codable过滤无效数据的方案
针对你的需求——过滤掉no值小于等于0的条目,我给你两种实用的实现方式,都是基于Codable的类型安全特性来做的:
方式一:先解码完整数组,再过滤有效数据
这种方式和你之前用Alamofire处理的逻辑最接近:先把所有数据解码成模型数组,再用filter筛选出符合条件的条目。
步骤1:定义完整的模型结构
首先要把JSON的外层结构也定义成Codable模型,覆盖顶层的data、里面的result、total_count和list:
// 顶层API响应模型 struct ApiResponse: Codable { let data: ResponseData } // data字段对应的模型 struct ResponseData: Codable { let result: Int let totalCount: Int let list: [SampleModel] // 处理JSON蛇形命名到Swift驼峰命名的映射 enum CodingKeys: String, CodingKey { case result case totalCount = "total_count" case list } } // 单个条目模型 struct SampleModel: Codable { let no: Int let category: Int let templateSeq: Int enum CodingKeys: String, CodingKey { case no case category case templateSeq = "template_seq" } }
步骤2:解码后过滤数据
解码完成后,直接对list数组进行过滤即可:
if let jsonData = jsonString.data(using: .utf8) { do { let apiResponse = try JSONDecoder().decode(ApiResponse.self, from: jsonData) // 过滤掉no<=0的无效条目 let validSamples = apiResponse.data.list.filter { $0.no > 0 } print("有效条目数量:\(validSamples.count)") // 在这里使用validSamples即可 } catch { print("解码失败:\(error.localizedDescription)") } }
这种方式简单直接,和你之前手动遍历字典的逻辑一致,而且全程类型安全,不需要繁琐的强制类型转换。
方式二:在解码过程中直接过滤(更优雅)
如果想把过滤逻辑整合到解码流程里,可以自定义ResponseData的解码方法,在解码list的时候就直接过滤掉无效条目:
修改后的ResponseData模型
struct ResponseData: Codable { let result: Int let totalCount: Int let list: [SampleModel] enum CodingKeys: String, CodingKey { case result case totalCount = "total_count" case list } // 自定义解码逻辑 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 先解码基础字段 result = try container.decode(Int.self, forKey: .result) totalCount = try container.decode(Int.self, forKey: .totalCount) // 先解码所有条目,再过滤 let allSamples = try container.decode([SampleModel].self, forKey: .list) // 只保留no>0的有效条目 list = allSamples.filter { $0.no > 0 } } }
解码代码
此时解码后直接拿到的apiResponse.data.list就是已经过滤好的有效数据:
if let jsonData = jsonString.data(using: .utf8) { do { let apiResponse = try JSONDecoder().decode(ApiResponse.self, from: jsonData) print("已过滤的有效条目数量:\(apiResponse.data.list.count)") // 直接使用apiResponse.data.list即可 } catch { print("解码失败:\(error.localizedDescription)") } }
额外说明:如果想让无效条目抛出解码错误
如果你希望当存在no<=0的条目时,直接触发解码错误(而不是跳过),可以在SampleModel的自定义解码方法里添加校验:
struct SampleModel: Codable { let no: Int let category: Int let templateSeq: Int enum CodingKeys: String, CodingKey { case no case category case templateSeq = "template_seq" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) no = try container.decode(Int.self, forKey: .no) category = try container.decode(Int.self, forKey: .category) templateSeq = try container.decode(Int.self, forKey: .templateSeq) // 校验no的有效性,无效则抛出解码错误 guard no > 0 else { throw DecodingError.dataCorruptedError( forKey: .no, in: container, debugDescription: "无效的no值:\(no),必须大于0" ) } } }
这种情况下,如果JSON里存在no<=0的条目,整个解码过程会抛出错误,你可以在catch块里针对性处理这种情况。
内容的提问来源于stack exchange,提问作者Michael Park
相关产品推荐
相关产品推荐

