You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用泛型KeyPath<Root, Value>创建兼容iOS15的NSPredicate?

用泛型KeyPath<Root, Value>初始化兼容iOS 15的NSPredicate方案

需求:通过泛型KeyPath<Root, Value>初始化NSPredicate,需兼容iOS 15,且必须保留编译期安全性(拒绝接收String类型键路径参数)。

之前的失败尝试

尝试1

func makeNSPredicate<Root, Value>(keyPath: KeyPath<Root,Value>, value: Value) -> NSPredicate {
    NSPredicate(format: "%K == '\(value)'", argumentArray: [keyPath])
}

错误:运行时崩溃(signal SIGABRT)
原因:KeyPath无法直接作为谓词参数,类型不匹配导致运行时错误。

尝试2

func makeNSPredicate<Root, Value>(keyPath: KeyPath<Root,Value>, value: Value) -> NSPredicate {
    NSPredicate(format: "%K == '\(value)'", keyPath)
}

错误:编译失败,提示Argument type 'KeyPath<Root, Value>' does not conform to expected type 'CVarArg'
原因:KeyPath未遵守CVarArg协议,不能直接传入NSPredicate(format:)的可变参数列表。

尝试3

func makeNSPredicate<Root, Value>(keyPath: KeyPath<Root,Value>, value: Value) -> NSPredicate {
    NSPredicate(format: "%K == '\(value)'", #keyPath(keyPath))
}

错误:编译失败,提示Argument of '#keyPath' refers to non-'@objc' property 'keyPath'
原因:#keyPath()仅适用于标记为@objc的属性,不能作用于KeyPath类型的变量。

兼容iOS 15的解决方案

使用NSExpression(forKeyPath:)将KeyPath转换为字符串键路径(该API从iOS 13开始支持,满足iOS 15兼容要求),同时通过谓词占位符安全传递值:

func makeNSPredicate<Root, Value>(keyPath: KeyPath<Root, Value>, value: Value) -> NSPredicate {
    let keyPathString = NSExpression(forKeyPath: keyPath).keyPath
    return NSPredicate(format: "%K == %@", keyPathString, value as CVarArg)
}

注意事项

  • 确保Value类型可以桥接到Objective-C(如基础数据类型、NSString/NSNumber等,或标记为@objc的自定义类型),否则需额外处理类型转换
  • 用%@作为值的占位符,避免直接字符串插值带来的特殊字符转义问题,同时保证类型安全

内容的提问来源于stack exchange,提问作者Oliver Pearmain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 08:33:24