我正在从CNContact获取联系人,花了.30秒来显示UI中的数千个联系人。我的客户希望我将时间缩短到0.01秒。他给了我Telegram app的例子。任何人都可以提供帮助
Ex Code:
typealias ContactsHandler =(_ contacts:[CNContact],_ error:NSError?) - >空隙
扩展名CDContactsPickerVC {
func getContacts(_ completion: @escaping ContactsHandler) {
if contactsStore == nil {
//ContactStore is control for accessing the Contacts
contactsStore = CNContactStore()
}
let error = NSError(domain: "CDContactPickerErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "No Contacts Access"])
switch CNContactStore.authorizationStatus(for: CNEntityType.contacts) {
case CNAuthorizationStatus.denied, CNAuthorizationStatus.restricted:
//User has denied the current app to access the contacts.
let productName = Bundle.main.infoDictionary!["CFBundleName"]!
let alert = UIAlertController(title: "Unable to access contacts", message: "\(productName) does not have access to contacts. Kindly enable it in privacy settings ", preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: { action in
completion([], error)
})
alert.addAction(okAction)
self.present(alert, animated: true, completion: nil)
case CNAuthorizationStatus.notDetermined:
//This case means the user is prompted for the first time for allowing contacts
contactsStore?.requestAccess(for: CNEntityType.contacts, completionHandler: { (granted, error) -> Void in
//At this point an alert is provided to the user to provide access to contacts. This will get invoked if a user responds to the alert
if (!granted ){
DispatchQueue.main.async(execute: { () -> Void in
completion([], error! as NSError?)
})
}
else{
self.getContacts(completion)
}
})
case CNAuthorizationStatus.authorized:
//Authorization granted by user for this app.
var contactsArray = [CNContact]()
let contactFetchRequest = CNContactFetchRequest(keysToFetch: allowedContactKeys())
do {
try contactsStore?.enumerateContacts(with: contactFetchRequest, usingBlock: { (contact, stop) -> Void in
//Ordering contacts based on alphabets in firstname
contactsArray.append(contact)
var key: String = "#"
//If ordering has to be happening via family name change it here.
if let firstLetter = contact.givenName[0..<1] , firstLetter.containsAlphabets() {
key = firstLetter.uppercased()
}
var contacts = [CNContact]()
if let segregatedContact = self.orderedContacts[key] {
contacts = segregatedContact
}
var identifierArray = [String]()
for contactDict in self.orderedContacts {
let contactArray = contactDict.value as [CNContact]
for cnObj in contactArray {
identifierArray.append(cnObj.identifier)
}
}
if identifierArray.contains(contact.identifier) {
// do nothing
}else {
contacts.append(contact)
self.orderedContacts[key] = contacts
}
})
self.sortedContactKeys = Array(self.orderedContacts.keys).sorted(by: <)
if self.sortedContactKeys.first == "#" {
self.sortedContactKeys.removeFirst()
self.sortedContactKeys.append("#")
}
completion(contactsArray, nil)
}
//Catching exception as enumerateContactsWithFetchRequest can throw errors
catch let error as NSError {
print(error.localizedDescription)
}
}
}
func allowedContactKeys() -> [CNKeyDescriptor]{
//We have to provide only the keys which we have to access. We should avoid unnecessary keys when fetching the contact. Reducing the keys means faster the access.
return [CNContactNamePrefixKey as CNKeyDescriptor,
CNContactGivenNameKey as CNKeyDescriptor,
CNContactFamilyNameKey as CNKeyDescriptor,
CNContactPhoneNumbersKey as CNKeyDescriptor,
CNContactEmailAddressesKey as CNKeyDescriptor,
]
}
// MARK: - Contact Operations
open func reloadContacts() {
DispatchQueue.global(qos: .background).async {
self.getContacts( {(contacts, error) in
if (error == nil) {
DispatchQueue.main.async(execute: {
self.emptyContactLabel.isHidden = contacts.count > 0 ? true : false
self.tableView.reloadData()
})
self.updateContactsInLocalDB(contacts: contacts)
}
})
}
}