如何使用具有长联系人列表的 Apple 联系人框架更快地获取 iOS 联系人?
How to fetch iOS Contacts more quickly using Apple's Contacts framework having long list of contacts?
我正在使用 CNContacts 在我的 iOS 设备中获取 phone 联系人。
当我的 phone 中有少量联系人时(比如 50 个),可以轻松获取联系人。
但是,当我有很多联系人(比如 500-700)时,hangs/waits 很长时间才能从 iOS phonebook 中获取这些联系人到我的应用程序数组中.
之前我用的是https://github.com/Alterplay/APAddressBook,它是以前Apple框架的快速库,但现在我使用的是最新的Apple框架。
我获取联系人的代码是....
#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];
}
}];
}
我试图以 20 个为一组获取联系人,每次都重新加载 table。但是这里它不能在调度线程中重新加载,或者只是崩溃。
如何改进此代码以快速获取联系人?
谢谢。
正如 Toro 提到的,requestAccessForEntityType: completionHandler:
方法不是 运行 在主 (UI) 线程上。从 documentation 你可以看到它提到:
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.
因此,任何您想在 UI 中进行的更新都必须在主线程中进行。
dispatch_async(dispatch_get_main_queue(), ^{
//Update UI on the Main thread, like reloading a UITableView
});
我正在使用 CNContacts 在我的 iOS 设备中获取 phone 联系人。
当我的 phone 中有少量联系人时(比如 50 个),可以轻松获取联系人。
但是,当我有很多联系人(比如 500-700)时,hangs/waits 很长时间才能从 iOS phonebook 中获取这些联系人到我的应用程序数组中.
之前我用的是https://github.com/Alterplay/APAddressBook,它是以前Apple框架的快速库,但现在我使用的是最新的Apple框架。
我获取联系人的代码是....
#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];
}
}];
}
我试图以 20 个为一组获取联系人,每次都重新加载 table。但是这里它不能在调度线程中重新加载,或者只是崩溃。
如何改进此代码以快速获取联系人?
谢谢。
正如 Toro 提到的,requestAccessForEntityType: completionHandler:
方法不是 运行 在主 (UI) 线程上。从 documentation 你可以看到它提到:
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.
因此,任何您想在 UI 中进行的更新都必须在主线程中进行。
dispatch_async(dispatch_get_main_queue(), ^{
//Update UI on the Main thread, like reloading a UITableView
});