Obtenga una lista de todos los contactos en iOS

Quiero obtener una lista de todos los contactos de un iPhone.

Comprobé la referencia de la Address Book , es posible que haya omitido algo, pero no vi que proporcione un método para obtener una lista de contactos.

¿Quizás la función ABPerson ABAddressBookCopyArrayOfAllPeople podría funcionar?

Ejemplo :

 ABAddressBookRef addressBook = ABAddressBookCreate( ); CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook ); CFIndex nPeople = ABAddressBookGetPersonCount( addressBook ); for ( int i = 0; i < nPeople; i++ ) { ABRecordRef ref = CFArrayGetValueAtIndex( allPeople, i ); ... } 

En mi respuesta original, al final de esta respuesta, muestro cómo recuperar contactos en versiones de iOS anteriores a la 9.0 de una manera que aborda algunos de los problemas que implican otras respuestas aquí.

Pero, si solo es compatible con iOS 9 y posterior, uno debe usar el marco de Contacts , evitando algunos de los molestos problemas de conexión que conlleva cuando se utiliza el marco anterior de la AddressBook .

Entonces, en iOS 9, usarías el marco de Contacts :

 @import Contacts; 

También necesita actualizar su Info.plist , agregando un NSContactsUsageDescription para explicar por qué su aplicación requiere acceso a los contactos.

Y luego haz algo como lo siguiente:

 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); } }]; 

A continuación está mi respuesta aplicable si es compatible con las versiones de iOS anteriores a iOS 9.0.

Un par de reacciones no solo a su pregunta, sino también a muchas de las respuestas proporcionadas aquí (que no solicitan permiso, no manejan los errores ABAddressBookCreateWithOptions correctamente o tienen fugas):

  1. Obviamente, importe el marco AddressBook :

     #import  

    o

     @import AddressBook; 
  2. Debe solicitar permiso para que la aplicación acceda a los contactos. Por ejemplo:

     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); }); 
  3. Tenga en cuenta que arriba, no he usado el patrón sugerido por otros:

     CFErrorRef *error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error); 

    Eso no es correcto. Como verá más arriba, quiere:

     CFErrorRef error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); 

    El primer patrón no capturará el error correctamente, mientras que el último lo hará. Si el error no fue NULL , no se olvide de CFRelease (o transferir la propiedad a ARC como lo hice) o de lo contrario perderá ese objeto.

  4. Para iterar a través de los contactos, desea:

     - (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(@"============================================="); } } 
  5. Quiero llamar su atención sobre un detalle bastante clave, a saber, la "Regla de Crear" :

    Las funciones de Core Foundation tienen nombres que indican cuándo posee un objeto devuelto:

    • Funciones de creación de objetos que tienen " Create " incrustado en el nombre;

    • Funciones de duplicación de objetos que tienen " Copy " incrustada en el nombre.

    Si posee un objeto, es su responsabilidad renunciar a la propiedad (utilizando CFRelease) cuando haya terminado con él.

    Esto significa que usted es responsable de liberar cualquier objeto devuelto por cualquier función de Core Foundation con Create o Copy en el nombre. Puede llamar a CFRelease explícitamente (como hice anteriormente con la addressBook y los phoneNumbers ) o, para objetos que admiten el puente gratuito, puede transferir la propiedad a ARC con __bridge_transfer o CFBridgingRelease (como hice anteriormente con allPeople , lastName , firstName , y phoneNumber ).

    El analizador estático (presione shift + command + B en Xcode o elija "Analizar" en el menú "Producto") puede identificar muchas situaciones en las que omitió observar esta "Crear regla" y no pudo liberar los objetos apropiados. Por lo tanto, cada vez que escriba código de Core Foundation como este, siempre ejecútelo a través del analizador estático para asegurarse de que no tenga ninguna fuga obvia.

Use este código para mostrar todos los nombres + apellidos + números de teléfono (iOS 6). Funciona en el simulador también:

 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(@"============================================="); } 

Asegúrate de tener la importación correcta

 #import  

Luego puede obtener un objeto CFArray con todos los contactos usando

 CFArrayRef ABAddressBookCopyArrayOfAllPeople (ABAddressBookRef addressBook); 

En iOS 6, asegúrese de utilizar ABAddressBookCreateWithOptions , que es la versión actualizada de 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 } 

Actualización para iOS 9.0 . Apple ha desaprobado la AddressBook y ahora han agregado el marco de Contacts :

Agregue la propiedad CNContactStore y CNContactStore esta manera:

 self.contactsStrore = [[CNContactStore alloc] init]; 

A continuación, agregue estos métodos para leer todos los contactos:

 -(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; } } 

Antes de iOS 9.0 => Usar el marco de AddressBook . Primero debe verificar el acceso y solicitar acceso a los contactos del Usuario:

 // 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; } } 

Gracias a mahesh y wzbozon, el siguiente código funcionó para mí:

 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]; } }); } }); 

Versión Swift:

 override func viewDidLoad() { super.viewDidLoad() var error: Unmanaged? 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...fromOpaque(COpaquePointer(CFArrayGetValueAtIndex(allPeople, index))).takeUnretainedValue() let firstName: String = ABRecordCopyValue(person, kABPersonFirstNameProperty).takeUnretainedValue() as? String println("\(firstName.debugDescription)") } } 

Consulte https://github.com/heardrwt/RHAddressBook (254 stars 01/2014).

Proporciona un contenedor ObjC para AddressBook con API mucho más simple.

Esto funciona para ios 7 e ios 8, espero que te ayude ………….

 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!$_" to "work" and "_$!!$_" 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 ); ... } 

Esta es una demostración completa para buscar todos los contactos con vista de tabla.

 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 } } 

si desea ordenar alfabéticamente, puede usar el código siguiente.

  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); 
    Intereting Posts