如何通过字符串键名获取Codable结构体实例的对应属性值
解决方法
针对你需要通过服务端返回的CodingKey原始值读取结构体属性、过滤数组的需求,提供两种可直接落地的方案:
方案1:预构建映射表(性能最优,推荐生产环境使用)
提前把服务端键和属性的对应关系写死成映射表,过滤大数组时性能开销最低,适合属性稳定的场景:
- 先添加辅助类型解决
Any无法直接判等的问题
struct AnyEquatable: Equatable { let value: Any private let equals: (Any) -> Bool init<T: Equatable>(_ value: T) { self.value = value self.equals = { other in guard let other = other as? T else { return false } return value == other } } static func == (lhs: AnyEquatable, rhs: AnyEquatable) -> Bool { lhs.equals(rhs.value) } }
- 给
Stuff添加扩展,实现取值和过滤能力
extension Stuff { // 服务端编码键和属性KeyPath的映射表,新增属性只需在这里补一行即可 static let serverKeyPathMap: [String: PartialKeyPath<Stuff>] = [ CodingKeys.id.rawValue: \.id, CodingKeys.coreRange.rawValue: \.coreRange ] /// 根据服务端传入的键获取对应属性值 func getValue(forServerKey key: String) -> Any? { guard let keyPath = Self.serverKeyPathMap[key] else { return nil } return self[keyPath: keyPath] } /// 校验当前实例是否符合服务端传入的过滤条件 func matches(conditions: [String: Any]) -> Bool { conditions.allSatisfy { key, expectedValue in guard let currentValue = getValue(forServerKey: key) else { return false } return AnyEquatable(currentValue) == AnyEquatable(expectedValue) } } }
- 调用示例
// 单个实例取值 let x = Stuff(id: "42", coreRange: true) let bananaValue = x.getValue(forServerKey: "Banana") // Optional("42") // 数组过滤,比如服务端返回过滤条件为 id等于Cheese、coreRange等于true let filterConditions: [String: Any] = ["Banana": "Cheese", "CR": true] let filteredList = stuffArray.filter { $0.matches(conditions: filterConditions) }
方案2:反射自动匹配(无需手动维护映射表)
如果你的结构体属性频繁调整,不想手动维护映射表,可以用Swift的Mirror反射自动匹配属性,性能略低于方案1,但50个属性的场景完全够用:
只需要把上面扩展里的serverKeyPathMap和getValue替换成下面的实现即可,其他逻辑完全一致:
extension Stuff { func getValue(forServerKey key: String) -> Any? { // 先把服务端键转成对应的CodingKeys成员,拿到属性名 guard let codingKey = CodingKeys(rawValue: key) else { return nil } let propertyName = codingKey.stringValue // 反射遍历属性匹配取值 let mirror = Mirror(reflecting: self) return mirror.children.first { $0.label == propertyName }?.value } }
注意事项
- 如果结构体属性包含可选类型,反射取值时会拿到嵌套的Optional值,判等前可根据业务需要提前解包
- 如果属性数量超过100、待过滤数组长度超过10万条,优先选择方案1,性能差距会非常明显
内容的提问来源于stack exchange,提问作者zaitsman
相关产品推荐
相关产品推荐

