Получить список всех контактов на iOS
Я хочу получить список всех контактов iPhone.
проверил Address Book
ссылка, я могу пропустить что-то, но я не видел, что он предоставляет метод, чтобы получить список контактов.
13 ответов:
возможно
ABPerson
функции ABAddressBookCopyArrayOfAllPeople может сделать?ABAddressBookRef addressBook = ABAddressBookCreate( ); CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook ); CFIndex nPeople = ABAddressBookGetPersonCount( addressBook ); for ( int i = 0; i < nPeople; i++ ) { ABRecordRef ref = CFArrayGetValueAtIndex( allPeople, i ); ... }
в моем первоначальном ответе в конце этого ответа я показываю, как получить контакты в версиях iOS до 9.0 таким образом, чтобы решить некоторые проблемы, связанные с другими ответами здесь.
но, если только поддержка iOS 9 и выше, нужно использовать
Contacts
рамки, избегая некоторых раздражающих проблем с мостами, связанных с использованием более старыхAddressBook
основы.Итак, в iOS 9 вы бы использовали
Contacts
основа:@import Contacts;
вы также необходимо обновить
Info.plist
добавлениеNSContactsUsageDescription
чтобы объяснить, почему ваше приложение требует доступ к контактам.а затем сделать что-то вроде следующего:
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; if (status == CNAuthorizationStatusDenied || status == CNAuthorizationStatusRestricted) { UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Access to contacts." message:@"This app requires access to contacts because ..." preferredStyle:UIAlertControllerStyleActionSheet]; [alert addAction:[UIAlertAction actionWithTitle:@"Go to Settings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil]; }]]; [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel 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; } // build array of contacts NSMutableArray *contacts = [NSMutableArray array]; NSError *fetchError; CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactIdentifierKey, [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName]]]; BOOL success = [store enumerateContactsWithFetchRequest:request error:&fetchError usingBlock:^(CNContact *contact, BOOL *stop) { [contacts addObject:contact]; }]; if (!success) { NSLog(@"error = %@", fetchError); } // you can now do something with the list of contacts, for example, to show the names CNContactFormatter *formatter = [[CNContactFormatter alloc] init]; for (CNContact *contact in contacts) { NSString *string = [formatter stringFromContact:contact]; NSLog(@"contact = %@", string); } }];
Ниже приведен мой ответ, применимый при поддержке версий iOS до iOS 9.0.
--
несколько реакций не только на ваш вопрос, но и на многие ответы, представленные здесь (которые либо не запрашивают разрешения, не обрабатывают
ABAddressBookCreateWithOptions
ошибки правильно, или утечка):
очевидно, импортировать
AddressBook
основа:#import <AddressBook/AddressBook.h>
или
@import AddressBook;
вы должны запросить разрешение для приложения, чтобы получить доступ к контактам. Например:
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); if (status == kABAuthorizationStatusDenied || status == kABAuthorizationStatusRestricted) { // if you got here, user had previously denied/revoked permission for your // app to access the contacts and all you can do is handle this gracefully, // perhaps telling the user that they have to go to settings to grant access // to contacts [[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; return; } CFErrorRef error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); if (!addressBook) { NSLog(@"ABAddressBookCreateWithOptions error: %@", CFBridgingRelease(error)); return; } ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { if (error) { NSLog(@"ABAddressBookRequestAccessWithCompletion error: %@", CFBridgingRelease(error)); } if (granted) { // if they gave you permission, then just carry on [self listPeopleInAddressBook:addressBook]; } else { // however, if they didn't give you permission, handle it gracefully, for example... dispatch_async(dispatch_get_main_queue(), ^{ // BTW, this is not on the main thread, so dispatch UI updates back to the main queue [[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; }); } CFRelease(addressBook); });
обратите внимание, что выше, я не использовал шаблон, предложенный другим:
CFErrorRef *error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
это неверно. Как вы увидите выше, вы хотите:
CFErrorRef error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
прежняя картина не будет захватить ошибку правильно, в то время как последний будет. Если
error
не былоNULL
не забудьтеCFRelease
это (или передать право собственности на ARC, как я сделал), иначе вы будете пропускать этот объект.чтобы перебрать контакты, вы хотите:
- (void)listPeopleInAddressBook:(ABAddressBookRef)addressBook { NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook)); NSInteger numberOfPeople = [allPeople count]; for (NSInteger i = 0; i < numberOfPeople; i++) { ABRecordRef person = (__bridge ABRecordRef)allPeople[i]; NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty)); NSString *lastName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty)); NSLog(@"Name:%@ %@", firstName, lastName); ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty); CFIndex numberOfPhoneNumbers = ABMultiValueGetCount(phoneNumbers); for (CFIndex j = 0; j < numberOfPhoneNumbers; j++) { NSString *phoneNumber = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phoneNumbers, j)); NSLog(@" phone:%@", phoneNumber); } CFRelease(phoneNumbers); NSLog(@"============================================="); } }
хочу обратить ваше внимание на довольно ключевую деталь, а именно "Создать Правило":
основные функции фонда имеют имена, укажите, когда у вас есть возвращаемый объект:
функции создания объектов, которые имеют "
Create
" встроенный в имени;объект-дублирование функций "
Copy
" встроенный в имя.если у вас есть объект, это ваша ответственность, чтобы отказаться от собственности (с помощью CFRelease), когда вы закончили с ним.
это означает, что вы несете ответственность за освобождение любого объекта, возвращаемого любой основной функцией Foundation с помощью
Create
илиCopy
в имя. Вы можете либо позвонитьCFRelease
явно (как я сделал выше сaddressBook
иphoneNumbers
) или, для объектов, которые поддерживают бесплатный мост, вы можете передать право собственности на ARC с__bridge_transfer
илиCFBridgingRelease
(как я сделал выше сallPeople
,lastName
,firstName
иphoneNumber
).статический анализатор (нажмите клавишу shift+команда+B в Xcode или выберите "анализ" из меню "продукт") может определить многие ситуации, в которых вы пренебрегли соблюдать это "правило создания" и не смогли освободить соответствующие объекты. Таким образом, всякий раз, когда вы пишете код Core Foundation, всегда запускайте его через статический анализатор, чтобы убедиться, что у вас нет никаких очевидных утечек.
используйте этот код для отображения всех имен + фамилий + телефонных номеров (iOS 6). Работает на симуляторе тоже:
CFErrorRef *error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error); CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook); for(int i = 0; i < numberOfPeople; i++) { ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i ); NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty)); NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty)); NSLog(@"Name:%@ %@", firstName, lastName); ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty); for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) { NSString *phoneNumber = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(phoneNumbers, i); NSLog(@"phone:%@", phoneNumber); } NSLog(@"============================================="); }
убедитесь, что у вас есть соответствующие импортные
#import <AddressBook/AddressBook.h>
тогда вы можете получить объект CFArray со всеми контактами с помощью
CFArrayRef ABAddressBookCopyArrayOfAllPeople (ABAddressBookRef addressBook);
В iOS 6, убедитесь, что вы используете
ABAddressBookCreateWithOptions
, который является обновленной версиейABAddressBookCreate
CFErrorRef * error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error); CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook); for(int i = 0; i < numberOfPeople; i++){ ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i ); // More code here }
обновление на
iOS 9.0
. Apple устарелаAddressBook
и теперь они добавилиContacts
основа:добавить
CNContactStore
свойство и определить его следующим образом:self.contactsStrore = [[CNContactStore alloc] init];
затем добавьте эти методы для чтения всех контактов:
-(void)checkContactsAccess{ [self requestContactsAccessWithHandler:^(BOOL grandted) { if (grandted) { CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactNamePrefixKey, CNContactMiddleNameKey, CNContactPhoneNumbersKey]]; [self.contactsStrore enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) { NSLog(@"%@", contact.familyName); NSLog(@"%@", contact.givenName); NSLog(@"%@", contact.namePrefix); NSLog(@"%@", contact.middleName); NSLog(@"%@", contact.phoneNumbers); NSLog(@"============================================="); }]; } }]; } -(void)requestContactsAccessWithHandler:(void (^)(BOOL grandted))handler{ switch ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]) { case CNAuthorizationStatusAuthorized: handler(YES); break; case CNAuthorizationStatusDenied: case CNAuthorizationStatusNotDetermined:{ [self.contactsStrore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { handler(granted); }]; break; } case CNAuthorizationStatusRestricted: handler(NO); break; } }
перед iOS 9.0 = > использовать
AddressBook
основы. Вы должны сначала проверить доступ и запросить доступ к контактам пользователя:// Prompt the user for access to their Address Book data -(void)requestAddressBookAccess { YourViewController * __weak weakSelf = self; ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error) { if (granted) { dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf accessGrantedForAddressBook]; }); } }); } -(void)checkAddressBookAccess { switch (ABAddressBookGetAuthorizationStatus()) { // Update our UI if the user has granted access to their Contacts case kABAuthorizationStatusAuthorized: [self accessGrantedForAddressBook]; break; // Prompt the user for access to Contacts if there is no definitive answer case kABAuthorizationStatusNotDetermined : [self requestAddressBookAccess]; break; // Display a message if the user has denied or restricted access to Contacts case kABAuthorizationStatusDenied: case kABAuthorizationStatusRestricted: { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Privacy Warning" message:@"Permission was not granted for Contacts." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } break; default: break; } }
благодаря mahesh и wzbozon, следующий код работал для меня:
CFErrorRef * error = NULL; addressBook = ABAddressBookCreateWithOptions(NULL, error); ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { if (granted) { dispatch_async(dispatch_get_main_queue(), ^{ CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook); for(int i = 0; i < numberOfPeople; i++){ ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i ); NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty)); NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty)); NSLog(@"Name:%@ %@", firstName, lastName); ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty); NSMutableArray *numbers = [NSMutableArray array]; for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) { NSString *phoneNumber = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(phoneNumbers, i); [numbers addObject:phoneNumber]; } NSMutableDictionary *contact = [NSMutableDictionary dictionary]; [contact setObject:name forKey:@"name"]; [contact setObject:numbers forKey:@"numbers"]; [all_contacts addObject:contact]; } }); } });
Swift версия:
override func viewDidLoad() { super.viewDidLoad() var error: Unmanaged<CFErrorRef>? var addressBook: ABAddressBook = ABAddressBookCreateWithOptions(nil, &error).takeRetainedValue() if ABAddressBookGetAuthorizationStatus() == ABAuthorizationStatus.NotDetermined { ABAddressBookRequestAccessWithCompletion(addressBook, { (granted:Bool, error:CFErrorRef!) -> Void in self.populateFrom(addressBook: addressBook) }) } else if ABAddressBookGetAuthorizationStatus() == ABAuthorizationStatus.Authorized { self.populateFrom(addressBook: addressBook) } } func populateFrom(#addressBook:ABAddressBook){ let allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook).takeRetainedValue() let nPeople = ABAddressBookGetPersonCount(addressBook) for index in 0..<nPeople{ let person: ABRecordRef = Unmanaged<ABRecordRef>.fromOpaque(COpaquePointer(CFArrayGetValueAtIndex(allPeople, index))).takeUnretainedValue() let firstName: String = ABRecordCopyValue(person, kABPersonFirstNameProperty).takeUnretainedValue() as? String println("\(firstName.debugDescription)") } }
проверить https://github.com/heardrwt/RHAddressBook (254 звезды 01/2014).
предоставляет оболочку ObjC для адресной книги с гораздо более простым API.
это работает для ios 7 и ios 8, я надеюсь, что это поможет вам.............
NSMutableArray *result = [[NSMutableArray alloc] init]; CFErrorRef *error = nil; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error); __block BOOL accessGranted = NO; if (ABAddressBookRequestAccessWithCompletion != NULL){ dispatch_semaphore_t sema = dispatch_semaphore_create(0); ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { accessGranted = granted; dispatch_semaphore_signal(sema); }); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); } else{ accessGranted = YES; } if (accessGranted){ // If the app is authorized to access the first time then add the contact ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error); CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook); for (int i=0; i<numberOfPeople; i++){ CFStringRef phone; ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i); CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty); CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty); NSString *userName = @"NoName"; userName = [NSString stringWithFormat:@"%@ %@", firstName, lastName]; userName = [userName stringByReplacingOccurrencesOfString:@"(null)" withString:@""]; ABMutableMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty); CFIndex phoneNumberCount = ABMultiValueGetCount( phoneNumbers ); phone = nil; for ( CFIndex ind= 0; ind<phoneNumberCount; ind++ ){ CFStringRef phoneNumberLabel = ABMultiValueCopyLabelAtIndex( phoneNumbers, ind); CFStringRef phoneNumberValue = ABMultiValueCopyValueAtIndex( phoneNumbers, ind); // converts "_$!<Work>!$_" to "work" and "_$!<Mobile>!$_" to "mobile" // Find the ones you want here if (phoneNumberLabel != nil){ NSStringCompareOptions compareOptions = NSCaseInsensitiveSearch; if(CFStringCompare(phoneNumberLabel, CFSTR("mobile"),compareOptions)){ phone = phoneNumberValue; } phone = phoneNumberValue; NSStringCompareOptions compareOptionss = NSCaseInsensitiveSearch; if(!CFStringCompare(phone, CFSTR("1-800-MY-APPLE"),compareOptionss)){ continue; } NSMutableArray *theKeys = [NSMutableArray arrayWithObjects:@"name", @"small_name",@"phone", @"checked", nil]; NSMutableArray *theObjects = [NSMutableArray arrayWithObjects:userName, [userName lowercaseString],phone, @"NO", nil]; NSMutableDictionary *theDict = [NSMutableDictionary dictionaryWithObjects:theObjects forKeys:theKeys]; if (![[functions formatNumber:(__bridge NSString *)(phone)] isEqualToString:[[NSUserDefaults standardUserDefaults]valueForKey:@"phoneNumber"]]){ [result addObject:theDict]; } } } } } //sort array NSSortDescriptor * descriptor = [[NSSortDescriptor alloc] initWithKey:@"small_name" ascending:YES]; // 1 NSArray * sortedArray = [result sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]];
ABAddressBookRef addressBook = ABAddressBookCreate( ); CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook ); CFIndex nPeople = ABAddressBookGetPersonCount( addressBook ); for ( int i = 0; i < nPeople; i++ ) { ABRecordRef ref = CFArrayGetValueAtIndex( allPeople, i ); ... }
это полная демонстрация для извлечения всех контактов с табличным представлением.
import UIKit import ContactsUI import AddressBook import Contacts class ShowContactsVC: UIViewController,CNContactPickerDelegate,UITableViewDelegate,UITableViewDataSource { @IBOutlet weak var tableView: UITableView! let peoplePicker = CNContactPickerViewController() let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate var contacts = [CNContact]() var option : Int = 0 var userAccessGranted : Bool = false var dataArray : NSMutableArray? override func viewDidLoad() { super.viewDidLoad() peoplePicker.delegate = self self.checkIfUserAccessGranted() self.tableView.delegate = self self.tableView.dataSource = self navigationController!.navigationBar.barTintColor = UIColor.grayColor() if(self.userAccessGranted) { self.tableView.hidden = false fetchContacts() } } func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if dataArray == nil { return 0; } else{ return dataArray!.count } } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("TableCell", forIndexPath: indexPath) as! ContactsTableViewCell let data = dataArray![indexPath.row] as! Data; cell.lblName.text = data.name cell.imgContact.image = data.image return cell } func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { cell.backgroundColor = UIColor.cyanColor() } func checkIfUserAccessGranted() { appDelegate.requestForAccess { (accessGranted) -> Void in if accessGranted { self.userAccessGranted = true; }else{ self.userAccessGranted = false; } } } func fetchContacts() { dataArray = NSMutableArray() let toFetch = [CNContactGivenNameKey, CNContactImageDataKey, CNContactFamilyNameKey, CNContactImageDataAvailableKey] let request = CNContactFetchRequest(keysToFetch: toFetch) do{ try appDelegate.contactStore.enumerateContactsWithFetchRequest(request) { contact, stop in print(contact.givenName) print(contact.familyName) print(contact.identifier) var userImage : UIImage; // See if we can get image data if let imageData = contact.imageData { //If so create the image userImage = UIImage(data: imageData)! }else{ userImage = UIImage(named: "no_contact_image")! } let data = Data(name: contact.givenName, image: userImage) self.dataArray?.addObject(data) } } catch let err{ print(err) } self.tableView.reloadData() } func contactPickerDidCancel(picker: CNContactPickerViewController) { picker.dismissViewControllerAnimated(true, completion: nil) self.navigationController?.popToRootViewControllerAnimated(true) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } import UIKit class Data { let name : String let image : UIImage init(name : String, image : UIImage) { self.image = image self.name = name } }
Если вы хотите отсортировать в алфавитном порядке, вы можете использовать ниже код.
CFErrorRef *error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error); CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook); CFMutableArrayRef peopleMutable = CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(allPeople), allPeople); CFArraySortValues(peopleMutable, CFRangeMake(0, CFArrayGetCount(peopleMutable)), (CFComparatorFunction) ABPersonComparePeopleByName, kABPersonSortByFirstName);