ios - 使用 CNContacts (Swift) 实现搜索控制器的问题
问题描述
我正在开发一个小应用程序,我想实现一个搜索控制器,以便能够查询我检索到的联系人。我已成功检索系统联系人并将其显示在表格视图中。但是当我尝试实现一个搜索控制器来简化联系人的搜索时,我遇到了一个“无效的谓词”问题,我不知道如何解决它。
这是我的实际做法:
import UIKit
import Contacts
class PhoneContactsVC: UITableViewController {
var contactsArray = [CNContact]()
var contacts = [CNContact]()
var selectedContactCN = CNContact()
var searchController: UISearchController!
var searchResults = [CNContact]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self as UITableViewDelegate
tableView.dataSource = self
let store = CNContactStore()
retrieveContacts(from: store)
setColors()
let searchResultsController = UITableViewController(style: .insetGrouped)
searchResultsController.tableView.delegate = self
searchResultsController.tableView.dataSource = self
searchResultsController.tableView.rowHeight = 63
searchResultsController.tableView.register(FriendCell.self, forCellReuseIdentifier: "FriendCell")
searchController = UISearchController(searchResultsController: searchResultsController)
searchController.searchResultsUpdater = self
searchController.searchBar.sizeToFit()
searchController.searchBar.tintColor = .systemGreen
searchController.searchBar.delegate = self
searchController.searchBar.barTintColor = .systemGreen
definesPresentationContext = true
navigationItem.searchController = searchController
}
override func willMove(toParent parent: UIViewController?) { // tricky part in iOS 10
navigationController?.navigationBar.barTintColor = UIColor.systemGreen //previous color
super.willMove(toParent: parent)
}
private func setColors(){
navigationController?.navigationBar.barTintColor = UIColor.white
let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.black]
navigationController?.navigationBar.titleTextAttributes = textAttributes
navigationController?.navigationBar.tintColor = UIColor.systemBlue;
}
func filterResultsWithSearchString(searchString: String) {
let predicate: NSPredicate = CNContact.predicateForContacts(matchingName: searchString)
let keysToFetch = [CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactImageDataAvailableKey as CNKeyDescriptor, CNContactBirthdayKey as CNKeyDescriptor, CNContactImageDataKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor]
searchResults = try! CNContactStore().unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
}
func retrieveContacts(from store: CNContactStore) {
let containerId = store.defaultContainerIdentifier()
let predicate = CNContact.predicateForContactsInContainer(withIdentifier: containerId)
// 4
let keysToFetch = [CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactImageDataAvailableKey as CNKeyDescriptor, CNContactBirthdayKey as CNKeyDescriptor, CNContactImageDataKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor]
contactsArray = try! store.unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
contacts = contactsArray.sorted(by: {$0.givenName < $1.givenName})
contacts.removeAll(where: {$0.givenName == ""})
DispatchQueue.main.async { [weak self] in
self?.tableView.reloadData()
}
}
}
extension PhoneContactsVC: UISearchBarDelegate {
}
extension PhoneContactsVC: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let searchString = searchController.searchBar.text!
filterResultsWithSearchString(searchString: searchString)
let searchResultsController = searchController.searchResultsController as! UITableViewController
searchResultsController.tableView.reloadData()
}
}
extension PhoneContactsVC {
// 1
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contacts.count
}
// 2
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 3
let cell = self.tableView.dequeueReusableCell(withIdentifier: "ContactTableViewCell") as! ContactTableViewCell
let contact = searchController.isActive ? searchResults[indexPath.row] : contacts[indexPath.row]
if contact.birthday == nil {
cell.registeredBday.isHidden = true
}
else {
cell.registeredBday.isHidden = false
}
cell.nameLabel.text = "\(contact.givenName) \(contact.familyName)"
// 4
if contact.imageDataAvailable == true, let imageData = contact.imageData {
cell.contactImage.image = UIImage(data: imageData)
}
else {
cell.contactImage.image = UIImage(named: "MaLong")
}
return cell
}
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath{
selectedContactCN = contacts[indexPath.row]
return indexPath
}
}
我希望你能给我一个解决方案。谢谢大家!
解决方案
..因为您的谓词无效=)。更新代码如下:
func filterResultsWithSearchString(searchString: String) {
let keysToFetch = [CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactImageDataAvailableKey as CNKeyDescriptor, CNContactBirthdayKey as CNKeyDescriptor, CNContactImageDataKey as CNKeyDescriptor, CNContactPhoneNumbersKey as CNKeyDescriptor]
var predicate: NSPredicate!
if searchString.isEmpty {
let containerId = CNContactStore().defaultContainerIdentifier()
predicate = CNContact.predicateForContactsInContainer(withIdentifier: containerId)
}
else {
predicate = CNContact.predicateForContacts(matchingName: searchString)
}
do {
searchResults = try CNContactStore().unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
}
catch let error {
print("ERROR: \(error)")
}
}
...
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchController.isActive ? searchResults.count : contacts.count
}
推荐阅读
- reactjs - React Native 将电影的 api 数据显示到屏幕上
- angular - 为什么不在 Angular 中使用 new 运算符来创建依赖?
- java - 如何将本机查询打印到控制台?
- react-native - Stripe 如何与 google pay 和 apple pay 在 react native 中协同工作
- css - 如何更改图像静止加载部分的白色?
- flutter - 如何在 Flutter 中在锁屏上显示 Widget?
- c++ - 从总和为浮点数的数组中选取的随机数
- java - 如果出现错误 java,如何将数字转换为罗马数字和罗马数字
- python - Pygame:杀死精灵后存在精灵属性
- scrollview - 尝试显示以屏幕为中心的垂直滚动视图