如何在CNContactPickerViewController中用predicateForEnablingContact筛选符合指定正则的联系人?
需要在CNContactPickerViewController中通过predicateForEnablingContact,仅启用电话号码匹配正则表达式^\+1[2-9]\d{9}$的联系人(即联系人至少有一个号码符合该规则),但编写的NSPredicate始终触发无效错误。
尝试过的代码及对应错误:
- 第一种写法:
let predicate = NSPredicate(format: "ANY self.phoneNumbers.'value'.'stringValue' BEGINSWITH %@", "1111") contactPicker.predicateForEnablingContact = predicate
错误日志:
2023-06-11 21:31:15.703957+0100 Test2[9610:702640] [CNUI ERROR] Error when showing picker: Error Domain=CNErrorDomain Code=300 "(null)" UserInfo={CNValidationErrors=(
"Error Domain=CNErrorDomain Code=400 "Invalid Predicate" UserInfo={NSLocalizedDescription=Invalid Predicate, NSLocalizedFailureReason=The operation couldn’t be completed because its predicate is invalid.}"
- 第二种写法:
NSPredicate(format: "phoneNumbers.@count > 0 AND SUBQUERY(phoneNumbers, $phoneNumber, $phoneNumber.value.stringValue != nil).@count > 0")
错误日志:
predicate is invalid., CNKeyPaths=(\n "value.stringValue"\n)}"
CNContactPickerViewController的predicateForEnablingContact对谓词语法有严格限制,不能随意使用嵌套属性访问,必须遵循联系人框架支持的键路径和操作符规则。
符合需求的正确写法如下:
let usPhoneRegex = "^\\+1[2-9]\\d{9}$" let predicate = NSPredicate(format: "SUBQUERY(phoneNumbers, $num, $num.value.stringValue MATCHES %@).@count > 0", usPhoneRegex) contactPicker.predicateForEnablingContact = predicate
核心说明
- 必须用
SUBQUERY遍历phoneNumbers数组,对每个号码单独做正则校验 - 键路径
$num.value.stringValue是框架允许的标准访问方式,避免了之前写法中不必要的单引号或格式错误 - 使用
MATCHES操作符对接正则表达式,直接匹配目标规则^\+1[2-9]\d{9}$ - 通过
@count > 0判断联系人是否存在至少一个符合规则的号码
该谓词能被联系人框架正确解析,只会启用满足号码规则的联系人。
内容的提问来源于stack exchange,提问作者Fudgey

