如何使用NSPredicate基于自定义对象数组实现搜索?
刚好做过类似的需求,用NSPredicate来实现这种联系人搜索很合适,不过因为你的数据源是按section分组的二维数组,得先理清是要返回扁平化的结果还是保留section结构,下面给你两种实用的实现方式:
实现方案
1. 返回扁平化的搜索结果(一维数组)
如果不需要保留原有的section分组,只想拿到所有符合条件的WPH对象,可以先把二维数组转成一维,再用谓词筛选:
// 假设你的contactsWithSections是类里的私有变量 private var contactsWithSections = [[WPH]]() func searchFlatContacts(with searchStr: String) -> [WPH] { // 把二维数组扁平化,得到所有联系人的一维数组 let allContacts = contactsWithSections.flatMap { $0 } // 创建谓词:确保fName不为空,且前缀匹配搜索字符串(忽略大小写) let predicate = NSPredicate(format: "fName != nil AND fName BEGINSWITH[c] %@", searchStr) // 用谓词筛选符合条件的对象 return allContacts.filter { predicate.evaluate(with: $0) } }
2. 保留Section结构的搜索结果(二维数组)
如果需要保留原有的分组结构,只显示每个section里符合条件的联系人,可以遍历每个section单独筛选,再去掉空的section:
func searchSectionedContacts(with searchStr: String) -> [[WPH]] { let predicate = NSPredicate(format: "fName != nil AND fName BEGINSWITH[c] %@", searchStr) // 对每个section内的元素筛选,然后过滤掉没有匹配结果的空section return contactsWithSections.map { section in section.filter { predicate.evaluate(with: $0) } }.filter { !$0.isEmpty } }
关键细节说明
- 匹配规则调整:
- 如果你需要的是前缀匹配(比如搜"al"只返回alex、alena这种以al开头的),用
BEGINSWITH[c]; - 如果你需要包含匹配(比如搜"le"能匹配alex、alena),把
BEGINSWITH[c]换成CONTAINS[c]; - 去掉
[c]就会区分大小写,比如搜"Al"只会匹配首字母大写的对象。
- 如果你需要的是前缀匹配(比如搜"al"只返回alex、alena这种以al开头的),用
- 处理可选值:加上
fName != nil是为了避免fName为nil的对象被误匹配,让筛选逻辑更严谨。 - 为什么能用NSPredicate:因为WPH继承自NSObject,支持KVC访问属性,所以可以直接通过
"fName"这种路径来构建谓词。
内容的提问来源于stack exchange,提问作者Harendra Tiwari
相关产品推荐
相关产品推荐

