Swift 4中能否在NSPredicate内使用dropLast()扩展?替代方案是什么?
嘿,这个问题问得挺实在的——我来给你讲明白!
首先直接给结论:你不能在NSPredicate的format字符串里直接调用Swift的dropLast()方法。原因很简单:NSPredicate的格式化语法是基于Objective-C运行时和自己的表达式规则的,它只能识别Objective-C兼容的方法、KVC属性,还有它内置的那些表达式关键字。而dropLast()是Swift标准库专门给String类型加的扩展方法,Objective-C runtime根本“认不出”它,这么写运行时肯定会报错。
那想要实现类似的效果,有两种靠谱的替代方案,看你的使用场景来选:
方案一:内存过滤用Swift闭包(推荐,更Swift化)
如果你的需求是过滤内存中的数组(比如[YourModel]这种),完全没必要用NSPredicate,直接用Swift的filter闭包就能搞定,代码还更清晰:
// 假设items是你的模型数组,模型有name属性 let filteredItems = items.filter { $0.name.dropLast() == searchText }
这种方式不仅能直接用dropLast(),还能享受Swift类型安全的好处,小数据量下性能完全没问题。
方案二:必须用NSPredicate时,用它支持的字符串表达式模拟
如果因为业务需求必须用NSPredicate(比如配合Core Data查询、或者UIKit组件的过滤逻辑),那可以用NSPredicate支持的字符串操作来实现dropLast()的效果——本质就是取原字符串去掉最后一个字符的子串:
方法1:用NSPredicate内置的SUBSTRING表达式
// 先判断字符串长度大于0,避免length(name)-1出现负数导致崩溃 let predicate = NSPredicate(format: "length(name) > 0 AND SUBSTRING(name, 0, length(name) - 1) = %@", searchText)
方法2:借助Objective-C的NSString方法
因为NSPredicate能识别Objective-C的方法,而NSString有substringToIndex:方法,所以可以这么写:
let predicate = NSPredicate(format: "length(name) > 0 AND (name as NSString).substringToIndex:(length(name)-1) = %@", searchText)
这两种方法都能达到和name.dropLast()等价的效果,而且是NSPredicate能正确解析的语法。
内容的提问来源于stack exchange,提问作者kiwidude89

