在使用Swift4和Codable协议时,我遇到了以下问题-似乎没有办法允许JSONDecoder跳过数组中的元素。例如,我具有以下JSON:
[ { "name": "Banana", "points": 200, "description": "A banana grown in Ecuador." }, { "name": "Orange" } ] 和一个可编码的结构:
struct GroceryProduct: Codable { var name: String var points: Int var description: String? } 解码此json时
let decoder = JSONDecoder() let products = try decoder.decode([GroceryProduct].self, from: json) 结果products为空。这是可以预期的,因为JSON中的第二个对象没有"points"键,而points在GroceryProductstruct中不是可选的。
问题是如何允许JSONDecoder“跳过”无效对象? 问题来源于stack overflow
一种选择是使用包装器类型,尝试对给定值进行解码。nil如果不成功,则存储:
struct FailableDecodable
: Decodable {let base: Base?
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.base = try? container.decode(Base.self)
}
} 然后,我们可以解码这些数组,并GroceryProduct在Base占位符中填写以下内容:
import Foundation
let json = """ [ { "name": "Banana", "points": 200, "description": "A banana grown in Ecuador." }, { "name": "Orange" } ] """.data(using: .utf8)!
struct GroceryProduct : Codable { var name: String var points: Int var description: String? }
let products = try JSONDecoder() .decode([FailableDecodable ].self, from: json) .compactMap { $0.base } // .flatMap in Swift 4.0
print(products)
// [ // GroceryProduct( // name: "Banana", points: 200, // description: Optional("A banana grown in Ecuador.") // ) // ] 然后,我们.compactMap { $0.base }用于过滤掉nil元素(那些在解码时引发错误的元素)。
这将创建一个的中间数组[FailableDecodable ],这不应该成为问题。但是,如果您希望避免这种情况,则可以始终创建另一个包装器类型,该包装器类型将对来自无键容器的每个元素进行解码和解包:
struct FailableCodableArray : Codable {
var elements: [Element]
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
var elements = [Element]()
if let count = container.count {
elements.reserveCapacity(count)
}
while !container.isAtEnd {
if let element = try container
.decode(FailableDecodable<Element>.self).base {
elements.append(element)
}
}
self.elements = elements
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(elements)
}
} 然后,您将解码为:
let products = try JSONDecoder() .decode(FailableCodableArray .self, from: json) .elements
print(products)
// [ // GroceryProduct( // name: "Banana", points: 200, // description: Optional("A banana grown in Ecuador.") // ) // ]
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。