问题
I am using CNContacts to fetch phonebook contacts in my iOS device.
When I have a small number of contacts in my phone (say, 50) the contacts are fetched easily.
However, when I have a lot of contacts (say 500-700) it hangs/waits for a long time to fetch these contacts from iOS phonebook into my App's array.
Previously I used https://github.com/Alterplay/APAddressBook which was a fast library for the previous Apple framework, but now I am using the latest Apple framework.
My code to fetch contacts is ....
#pragma mark - Get All Contacts....
-(void)getAllContactsWithNewFrameworkOfApple {
NSMutableArray *_contactsArray = [[NSMutableArray alloc]init];
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
if (status == CNAuthorizationStatusDenied || status == CNAuthorizationStatusDenied) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"This app previously was refused permissions to contacts; Please go to settings and grant permission to this app so it can use contacts" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
// [self presentViewController:alert animated:TRUE completion:nil];
return;
}
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
// make sure the user granted us access
if (!granted) {
dispatch_async(dispatch_get_main_queue(), ^{
// user didn't grant access;
// so, again, tell user here why app needs permissions in order to do it's job;
// this is dispatched to the main queue because this request could be running on background thread
});
return;
}
NSError *fetchError;
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactIdentifierKey,CNContactGivenNameKey,CNContactFamilyNameKey,CNContactEmailAddressesKey,CNContactPhoneNumbersKey]];
BOOL success = [store enumerateContactsWithFetchRequest:request error:&fetchError usingBlock:^(CNContact *contact, BOOL *stop) {
[_contactsArray addObject:contact];
NSLog(@"I am %@", _contactsArray);
}];
if (!success) {
NSLog(@"error = %@", fetchError);
}else {
NSLog(@"End with Success %@", _contactsArray);
[self finalUsage:_contactsArray];
}
}];
}
I was trying to fetch contacts in batches of 20, reloading the table each time. However here it can't reload within the dispatch thread, or simply crashes.
How do I improve this code to fetch contacts quickly?
Thanks.
回答1:
As Toro mentioned, the requestAccessForEntityType: completionHandler:
method is not running on the main (UI) thread. From the documentation you can see it mentions that:
Users are able to grant or deny access to contact data on a per-application basis. Request access to contact data by calling requestAccessForEntityType:completionHandler: method. This will not block your application while the user is being asked for permission. The user will only be prompted the first time access is requested; any subsequent CNContactStore calls will use the existing permissions. The completion handler is called on an arbitrary queue. It is recommended that you use CNContactStore instance methods in this completion handler instead of the UI main thread. This method is optional when CNContactStore is used in the background thread. If this method is not used, CNContactStore may block your application while the user is asked for access permission.
So any updates you want to do in the UI, you'll have to do on the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
//Update UI on the Main thread, like reloading a UITableView
});
来源:https://stackoverflow.com/questions/33604817/how-to-fetch-ios-contacts-more-quickly-using-apples-contacts-framework-having-l