Solicitar acceso a contactos mediante progtwigción

Desde la actualización a iOS 6, he notado que mi código para agregar un contacto a la libreta de direcciones de iPhone ya no funciona. Creo que este es un problema relacionado con el permiso, ya que Apple ahora requiere permiso del usuario antes de acceder a los contactos (solucionando este problema).

Esperaba que la aplicación pidiera automáticamente permiso para acceder a contactos, como en la captura de pantalla a continuación, pero no funciona. Tratando de agregar el contacto simplemente falla con ABAddressBookErrorDomain error 1 .

¿Necesito iniciar el dialog de request de acceso a los contactos mediante progtwigción? ¿Cómo se hace eso?

contactos de acceso

De acuerdo con esta documentation en el sitio de Apple (desplácese hacia abajo a Privacidad en el medio de la página), se debe otorgar acceso a la libreta de direcciones antes de que se pueda acceder mediante progtwigción. Esto es lo que terminé haciendo.

  #import <AddressBookUI/AddressBookUI.h> // Request authorization to Address Book ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL); if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) { ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) { if (granted) { // First time access has been granted, add the contact [self _addContactToAddressBook]; } else { // User denied access // Display an alert telling user the contact could not be added } }); } else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) { // The user has previously given access, add the contact [self _addContactToAddressBook]; } else { // The user has previously denied access // Send an alert telling user to change privacy setting in settings app } 

Actualización para iOS 9 y posterior:

Desde el website de Apple:

Importante

El marco de trabajo de UI de la Libreta de direcciones está en desuso en iOS 9. Utilice las API definidas en el marco de ContactsUI en su lugar. Para get más información, vea ContactosUI

¡Eso hizo el truco perfecto para mí!

En iOS6, Apple introduce un nuevo control de privacidad, el usuario puede controlar el acceso del contacto y el calendar por cada aplicación. Por lo tanto, en el lado del código, debe agregar alguna forma de solicitar el permiso. En iOS5 o antes, siempre podemos llamar

 ABAddressBookRef addressBook = ABAddressBookCreate(); 

para get la libreta de direcciones sin ningún problema, pero en iOS6, si no tiene permiso, esta llamada solo devolverá el puntero vacío. Por eso necesitamos cambiar el método para get ABAddressBookRef.

 __block BOOL accessGranted = NO; if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6 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); dispatch_release(sema); } else { // we're on iOS 5 or older accessGranted = YES; } if (accessGranted) { // Do whatever you want here. } 

En el código, el semáforo se usa para bloquear hasta la respuesta, mientras que ABAddressBookRequestAccessWithCompletion solicitará permiso si la aplicación no pregunta antes. De lo contrario, solo seguirá las configuraciones en Configuración-Privacidad-Contacto.

FUENTE: http://programmerjoe.blogspot.com/2012/10/ios6-permissions-contacts.html

 ABAddressBookRef addressBook = ABAddressBookCreate(); __block BOOL accessGranted = NO; if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6 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); dispatch_release(sema); } else { // we're on iOS 5 or older accessGranted = YES; } if (accessGranted) { if(self.isContactsChanged) { { self.isContactsChanged=NO; CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); ABAddressBookRegisterExternalChangeCallback(addressBook, addressBookChanged, self); int allPeopleCount = CFArrayGetCount(allPeople); NSMutableArray *contactArrTemp = [[NSMutableArray alloc]init]; __block int noNumberCount=1; managedObjectContext = [(AppDelegate *)[[UIApplication shanetworkingApplication] delegate] managedObjectContext]; newMoc = [[NSManagedObjectContext alloc] init]; [newMoc setPersistentStoreCoordinator:[[AppDelegate getAppDelegate] persistentStoreCoordinator]]; [self DeleteAllPhoneContact]; NSNotificationCenter *notify = [NSNotificationCenter defaultCenter]; [notify addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:newMoc]; self.backgroundQueue = dispatch_queue_create("com.storephonecontacts.bgqueue", NULL); __block NSMutableDictionary *dic; __block NSString *strTime,*strName,*strMobile,*strEmail,*strNotes; __block NSDate *nsDate; dispatch_async(self.backgroundQueue, ^{ NSMutableDictionary *dict =nil; for (int i = 0; i < allPeopleCount; i++) { dic = [[NSMutableDictionary alloc]init]; ABRecordRef record = CFArrayGetValueAtIndex(allPeople,i); NSDate *date = (NSDate*)ABRecordCopyValue(record, kABPersonCreationDateProperty); nsDate = [date retain]; NSDateFormatter *formatterTime = [[NSDateFormatter alloc] init]; [formatterTime setDateFormat:@"hh.mm"]; NSString *dateStrPhone = [formatterTime stringFromDate:date]; strTime = [dateStrPhone retain]; [formatterTime release]; NSString *name = (NSString*)ABRecordCopyValue(record, kABPersonFirstNameProperty); if([name length]>0) name = [name stringByAppendingString:@" "]; NSString *name1 = (NSString*)ABRecordCopyValue(record, kABPersonLastNameProperty); if([name1 length]>0) { if([name length]>0) name = [name stringByAppendingString:name1]; else name = (NSString*)ABRecordCopyValue(record, kABPersonLastNameProperty); } if([name length]>0) strName = [name retain]; else strName = [@"noName" retain]; //to save notes NSString *notes = (NSString*)ABRecordCopyValue(record, kABPersonNoteProperty); if(notes == NULL){ strNotes = @"noNotes"; } else{ strNotes = [notes retain]; } //for image if (!ABPersonHasImageData(record)){ } else{ CFDataRef imageData = ABPersonCopyImageData(record); UIImage *image = [UIImage imageWithData:(NSData *) imageData]; [dic setObject:image forKey:@"image"]; CFRelease(imageData); } //To set Mobile NSMutableArray* mobileArray = [[NSMutableArray alloc] init]; ABMutableMultiValueRef multi = ABRecordCopyValue(record, kABPersonPhoneProperty); if (ABMultiValueGetCount(multi) > 0) { // collect all emails in array for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) { CFStringRef mobileRef = ABMultiValueCopyValueAtIndex(multi, i); CFStringRef locLabel = ABMultiValueCopyLabelAtIndex(multi, i); NSString *phoneLabel =(NSString*) ABAddressBookCopyLocalizedLabel(locLabel); if([phoneLabel isEqualToString:@"mobile"]) [mobileArray addObject:(NSString *)mobileRef]; else if([phoneLabel isEqualToString:@"iPhone"]) [mobileArray addObject:(NSString *)mobileRef]; else if([phoneLabel isEqualToString:@"home"]) [mobileArray addObject:(NSString *)mobileRef]; else if([phoneLabel isEqualToString:@"work"]) [mobileArray addObject:(NSString *)mobileRef]; else if([phoneLabel isEqualToString:@"main"]) [mobileArray addObject:(NSString *)mobileRef]; else if([phoneLabel isEqualToString:@"other"]) [mobileArray addObject:(NSString *)mobileRef]; CFRelease(mobileRef); CFRelease(locLabel); } } CFRelease(multi); if([mobileArray count]>0) strMobile = [[mobileArray objectAtIndex:0]retain]; else{ NSString *str=[NSString stringWithFormat:@"noNumber%i",noNumberCount]; strMobile = [str retain]; noNumberCount++; } [mobileArray release]; //To set E-mail NSMutableArray* emailArray = [[NSMutableArray alloc] init]; multi = ABRecordCopyValue(record, kABPersonEmailProperty); if (ABMultiValueGetCount(multi) > 0) { // collect all emails in array for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) { CFStringRef emailRef = ABMultiValueCopyValueAtIndex(multi, i); [emailArray addObject:(NSString *)emailRef]; CFRelease(emailRef); } } CFRelease(multi); if([emailArray count]>0) strEmail = [[emailArray objectAtIndex:0]retain]; else strEmail = [@"noemail" retain]; [emailArray release]; bool addBool = NO; if([strName isEqualToString:@"noName"]){ if([strEmail isEqualToString:@"noemail"]){ } else{ [dic setObject:strEmail forKey:@"name"]; addBool = YES; } if(addBool == NO){ if([strMobile isEqualToString:@"noNumber"]){ } else{ [dic setObject:strMobile forKey:@"name"]; addBool = YES; } } } else{ [dic setObject:strName forKey:@"name"]; addBool = YES; } [dic setObject:strEmail forKey:@"email"]; [dic setObject:strMobile forKey:@"mobile"]; [dic setObject:nsDate forKey:@"date"]; [dic setObject:strTime forKey:@"time"]; [dic setObject:strNotes forKey:@"notes"]; if(addBool == YES) [contactArrTemp addObject:dic]; if([strMobile hasPrefix:@"0"]){ NSString *contactNumber=[strMobile stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""]; if(contactNumber.length>7) [dic setObject:@"iPhone" forKey:@"ContactType"]; } else { if(strMobile.length>9) [dic setObject:@"iPhone" forKey:@"ContactType"]; } if(![[dic objectForKey:@"ContactType"] isKindOfClass:[NSNull class]] && [dic objectForKey:@"ContactType"]) { [self InsertContactWithContactInfoDictionary:dic]; } [strName release]; [nsDate release]; [strEmail release]; [strMobile release]; [strTime release]; [strNotes release]; [dic release]; } dispatch_async(self.backgroundQueue, ^(void){ [self gcdDidFinishaddfebriteParsing:dict]; }); dispatch_release(self.backgroundQueue); self.backgroundQueue=nil; }); } } else { [[NSNotificationCenter defaultCenter] postNotificationName:@"PhoneContactsSaved" object:nil userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:@"Successful"]]; [[NSNotificationCenter defaultCenter] postNotificationName:@"updateContacts" object:nil userInfo:[NSDictionary dictionaryWithObject:@"success" forKey:@"update"]]; } } 

Tuve algunos problemas con el código yunas en iOS6.1 en Xcode5. Con algunas pequeñas adaptaciones me funcionó.

El problema era que ARC en iOS 6 no permitía dispatch_release(sema); Aquí está el código de trabajo. Nota: uso m_addressbook lugar de la addressbook de addressbook como ABAddressBookRef!

ViewController.m

 #import "ViewController.h" #import <AddressBook/AddressBook.h> #import <AddressBook/ABAddressBook.h> #import <AddressBook/ABPerson.h> @interface ViewController () @property (nonatomic, strong) NSMutableArray* contactList; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; ABAddressBookRef m_addressbook = ABAddressBookCreateWithOptions(NULL, NULL); __block BOOL accessGranted = NO; if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6 dispatch_semaphore_t sema = dispatch_semaphore_create(0); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @autoreleasepool { // Write your code here... // Fetch data from SQLite DB } }); ABAddressBookRequestAccessWithCompletion(m_addressbook, ^(bool granted, CFErrorRef error) { accessGranted = granted; dispatch_semaphore_signal(sema); }); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); } else { // we're on iOS 5 or older accessGranted = YES; } if (accessGranted) { // do your stuff } } // ... 
 - (void)viewDidLoad { [super viewDidLoad]; [self loadPhoneContacts]; } -(void)loadPhoneContacts{ ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); if (status == kABAuthorizationStatusDenied) { // 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 (error) { NSLog(@"ABAddressBookCreateWithOptions error: %@", CFBridgingRelease(error)); if (addressBook) CFRelease(addressBook); return; } if (status == kABAuthorizationStatusNotDetermined) { // present the user the UI that requests permission to contacts ... 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]; }); } if (addressBook) CFRelease(addressBook); }); } else if (status == kABAuthorizationStatusAuthorized) { [self listPeopleInAddressBook:addressBook]; if (addressBook) CFRelease(addressBook); } } - (void)listPeopleInAddressBook:(ABAddressBookRef)addressBook { NSInteger numberOfPeople = ABAddressBookGetPersonCount(addressBook); NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook)); 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 i = 0; i < numberOfPhoneNumbers; i++) { NSString *phoneNumber = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phoneNumbers, i)); NSLog(@" phone:%@", phoneNumber); } CFRelease(phoneNumbers); NSLog(@"============================================="); } } 

Para el marco de contactos:

 - (void)checkPermissionForCNContacts { switch ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]) { case CNAuthorizationStatusNotDetermined: { [[[CNContactStore alloc] init] requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { if (granted == YES) [self showCNContactPicker]; }]; } break; case CNAuthorizationStatusRestricted: case CNAuthorizationStatusDenied: // Show custom alert break; case CNAuthorizationStatusAuthorized: [self showCNContactPicker]; break; } } 

Si alguien tiene un problema con la libreta de direcciones en iOS5, use

 ABAddressBookRef addressBook = ABAddressBookCreate(); 

Inscrito de

 ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL,NULL); 
 ABAddressBookRequestAccessWithCompletion(ABAddressBookCreateWithOptions(NULL, nil), ^(bool granted, CFErrorRef error) { dispatch_async(dispatch_get_main_queue(), ^{ if (!granted){ [[[UIAlertView alloc] initWithTitle:@"Contacts Access Denied" message:@"This app requires access to your device's Contacts.\n\nPlease enable Contacts access for this app in Settings / Privacy / Contacts" delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil] show]; } else { //access authorized } }); }); 

Para agregar una descripción al uso de alerta en InfoPlist.strings.

NSContactsUsageDescription = "TESTING!";

Swift 3. No te olvides de importar contactos.

 func requestForContactAccess(completionHandler: @escaping (_ accessGranted: Bool) -> Void) { let authorizationStatus = CNContactStore.authorizationStatus(for: CNEntityType.contacts) switch authorizationStatus { case .authorized: completionHandler(true) case .denied, .notDetermined: self.contactStore.requestAccess(for: CNEntityType.contacts, completionHandler: { (access, accessError) -> Void in if access { completionHandler(access) } else { if authorizationStatus == CNAuthorizationStatus.denied { DispatchQueue.main.async(execute: { () -> Void in let message = "\(accessError!.localizedDescription)\n\nPlease allow the app to access your contacts through the Settings." self.showMessage(message: message) }) } } }) default: completionHandler(false) } } 

Con iOS 6 tienes que pedir permiso como este

 requestAccessToEntityType:EKEntityTypeEvent completion: 

Para get la libreta de direcciones en ios

 - (void)retreiveAllContacts { ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL); CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook); if (!people) { return ; } CFMutableArrayRef peopleMutable = CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(people), people); CFArraySortValues(peopleMutable, CFRangeMake(0, CFArrayGetCount(peopleMutable)), (CFComparatorFunction) ABPersonComparePeopleByName, (void*) ABPersonGetSortOrdering()); NSMutableArray *contacts = [[NSMutableArray alloc] initWithCapacity:CFArrayGetCount(peopleMutable)]; for (CFIndex i = 0; i < CFArrayGetCount(peopleMutable); i++) { ABRecordRef person = CFArrayGetValueAtIndex(peopleMutable, i); int32_t recId = ABRecordGetRecordID(person); NSString * abId = [NSString stringWithFormat:@"%d", recId]; ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty); ABMultiValueRef emailIds = ABRecordCopyValue(person, kABPersonEmailProperty); NSString* firstName = (__bridge NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty); NSString* lastName = (__bridge NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty); NSString* companyName = (__bridge NSString*)ABRecordCopyValue(person, kABPersonOrganizationProperty); NSString* displayName = [firstName ? firstName : @"" stringByAppendingFormat:@" %@", lastName ? lastName : @""]; displayName = [displayName stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" "]]; NSMutableDictionary* contactInfo = [[NSMutableDictionary alloc] init]; if(ABPersonHasImageData(person)) { CFDataRef imageDataRef = ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail); NSData * imageData = (__bridge NSData *)imageDataRef; UIImage * thumbImage = [UIImage imageWithData:imageData]; [contactInfo setObject:thumbImage forKey:@"picture"]; } if(!firstName) firstName = @""; if (!lastName) lastName = @""; if(!displayName) displayName = @""; if(!companyName) companyName = @""; // [contactInfo setObject:[firstName capitalizedString] forKey:kFirstNameKey]; //[contactInfo setObject:[lastName capitalizedString] forKey:kLastNameKey]; [contactInfo setObject:[displayName capitalizedString] forKey:@"name"]; [contactInfo setObject:abId forKey:@"ABID"]; // [contactInfo setObject:companyName forKey:kCompanyNameKey]; NSMutableArray* phoneNumbersList = [[NSMutableArray alloc] init]; for (CFIndex j=0; j < ABMultiValueGetCount(phoneNumbers); j++) { NSString* phone = (__bridge NSString*)ABMultiValueCopyValueAtIndex(phoneNumbers, j); CFStringRef localizedLabel = ABMultiValueCopyLabelAtIndex(phoneNumbers,j); // NSString *phoneLabel =(__bridge NSString*) ABAddressBookCopyLocalizedLabel(localizedLabel); if( phone) { // NSLog(@"validatedPhone: %@", validatedPhone); [phoneNumbersList addObject:phone]; } if (localizedLabel) { // NSLog(@"localizedLabel: %@", localizedLabel); CFRelease(localizedLabel); } } if(phoneNumbers) { // NSLog(@"phoneNumbers: %@", phoneNumbers); CFRelease(phoneNumbers); // NSLog(@"phoneNumbers Release: %@", phoneNumbers); } [contactInfo setObject:phoneNumbersList forKey:@"phoneNumbers"]; NSMutableArray * emailList = [[NSMutableArray alloc] init]; for (CFIndex j=0; j < ABMultiValueGetCount(emailIds); j++) { NSString* email = (__bridge NSString*)ABMultiValueCopyValueAtIndex(emailIds, j); CFStringRef localizedLabel = ABMultiValueCopyLabelAtIndex(emailIds, j); if(email) { [emailList addObject:email]; } } if(emailIds) { CFRelease(emailIds); } if(emailList && [emailList count]) [contactInfo setObject:emailList forKey:@"emails"]; if ([phoneNumbersList count] > 0 || [emailList count] > 0) { [contacts addObject:contactInfo]; } } //CFRelease(); CFRelease(people); if([contacts count]) { [self createiOSContactsDataSourceWithFeed:contacts]; } } 

Este código muestra cómo configurar el permiso y cómo get todos los contactos del teléfono y mostrar los contactos en la list con la label de label

 var contactStore = CNContactStore() var contactArray = [CNContact]() func getContacts() { if CNContactStore.authorizationStatus(for: .contacts) == .notDetermined { contactStore.requestAccess(for: .contacts, completionHandler: { (authorized:Bool, error:Error?) in if authorized { let requestForContacts = CNContactFetchRequest(keysToFetch: [CNContactFormatter.descriptorForRequinetworkingKeys(for: CNContactFormatterStyle.fullName), CNContactPhoneNumbersKey as CNKeyDescriptor, CNContactImageDataKey as CNKeyDescriptor, CNContactNicknameKey as CNKeyDescriptor]) do{ try self.contactStore.enumerateContacts(with: requestForContacts) { (contacts : CNContact, stop: UnsafeMutablePointer<ObjCBool>) -> Void in self.contactArray.append(contacts) //print("hello") } } catch { print("EXCEPTION COUGHT") } } }) } else if CNContactStore.authorizationStatus(for: .contacts) == .authorized { let requestForContacts = CNContactFetchRequest(keysToFetch: [CNContactFormatter.descriptorForRequinetworkingKeys(for: CNContactFormatterStyle.fullName), CNContactPhoneNumbersKey as CNKeyDescriptor, CNContactImageDataKey as CNKeyDescriptor, CNContactNicknameKey as CNKeyDescriptor]) do{ try self.contactStore.enumerateContacts(with: requestForContacts) { (contacts : CNContact, stop: UnsafeMutablePointer<ObjCBool>) -> Void in self.contactArray.append(contacts) } } catch { } } } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. getContacts() } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { //print(contactArray) return contactArray.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "defaultCell") if cell != nil{ //var dig = String() var hmdig = [String]() let names = contactArray[indexPath.row] print(names) let name1 = names.givenName+" "+names.middleName+" "+names.familyName for number in names.phoneNumbers { let phoneNumber = number.value let dig = (phoneNumber.value(forKey: "digits") as? String)! hmdig.append(dig) } // Set the contact image. if let imageData = names.imageData { let myImage = cell?.viewWithTag(30) as! UIImageView myImage.image = UIImage(data: imageData) } // let niknm = names.nickname let nameLable1 = cell?.viewWithTag(10) as! UILabel nameLable1.text = name1 let nameLable2 = cell?.viewWithTag(20) as? UILabel nameLable2?.text = hmdig.joined(separator: ",\n") // let nameLable3 = cell?.viewWithTag(40) as? UILabel // nameLable3?.text = niknm return cell! } else{ return UITableViewCell() } }