4

iOS デバイスで電話帳の連絡先を取得するためにCNContactsを使用しています。

携帯電話に少数の連絡先 (たとえば 50 件) がある場合、連絡先は簡単に取得されます。

ただし、多くの連絡先 (500 ~ 700 など) がある場合、これらの連絡先を iOS 電話帳からアプリの配列に取得するために長時間ハング/待機します。

以前は、以前の Apple フレームワークの高速なライブラリであるhttps://github.com/Alterplay/APAddressBookを使用していましたが、現在は最新の 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 のバッチで連絡先をフェッチしようとしていました。ただし、ここでは、ディスパッチ スレッド内でリロードできないか、単にクラッシュします。

このコードを改善して連絡先をすばやく取得するにはどうすればよいですか?

ありがとう。

4

1 に答える 1

2

Toro が述べたように、requestAccessForEntityType: completionHandler:メソッドはメイン (UI) スレッドで実行されていません。ドキュメントから、次のことが言及されていることがわかります。

ユーザーは、アプリケーションごとに連絡先データへのアクセスを許可または拒否できます。requestAccessForEntityType:completionHandler: メソッドを呼び出して、連絡先データへのアクセスをリクエストします。これにより、ユーザーが許可を求められている間、アプリケーションがブロックされることはありません。ユーザーは、最初のアクセスが要求されたときにのみプロンプトが表示されます。以降の CNContactStore 呼び出しでは、既存のアクセス許可が使用されます。完了ハンドラは、任意のキューで呼び出されます。UI メイン スレッドではなく、この完了ハンドラーで CNContactStore インスタンス メソッドを使用することをお勧めします。バックグラウンド スレッドで CNContactStore が使用されている場合、このメソッドはオプションです。この方法を使用しないと、ユーザーがアクセス許可を求められている間、CNContactStore がアプリケーションをブロックする可能性があります。

したがって、UI で行う更新は、メイン スレッドで行う必要があります。

dispatch_async(dispatch_get_main_queue(), ^{
   //Update UI on the Main thread, like reloading a UITableView
});
于 2015-11-09T08:44:25.610 に答える